@athenaintel/react 0.24.1 → 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.
Files changed (145) hide show
  1. package/README.md +18 -0
  2. package/dist/assets/AssetPanel.cjs +3 -2
  3. package/dist/assets/AssetPanel.cjs.map +1 -1
  4. package/dist/assets/AssetPanel.js +3 -2
  5. package/dist/assets/AssetPanel.js.map +1 -1
  6. package/dist/assets/AthenaAssetEmbed.cjs +1 -0
  7. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  8. package/dist/assets/AthenaAssetEmbed.js +1 -0
  9. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  10. package/dist/assets/use-asset-embed.cjs +22 -23
  11. package/dist/assets/use-asset-embed.cjs.map +1 -1
  12. package/dist/assets/use-asset-embed.d.ts +9 -0
  13. package/dist/assets/use-asset-embed.js +22 -23
  14. package/dist/assets/use-asset-embed.js.map +1 -1
  15. package/dist/auth/AthenaAuthProvider.cjs +32 -4
  16. package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
  17. package/dist/auth/AthenaAuthProvider.d.ts +21 -0
  18. package/dist/auth/AthenaAuthProvider.js +33 -5
  19. package/dist/auth/AthenaAuthProvider.js.map +1 -1
  20. package/dist/auth/AthenaCredentialSourceContext.cjs +21 -0
  21. package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -0
  22. package/dist/auth/AthenaCredentialSourceContext.d.ts +14 -0
  23. package/dist/auth/AthenaCredentialSourceContext.js +21 -0
  24. package/dist/auth/AthenaCredentialSourceContext.js.map +1 -0
  25. package/dist/auth/AthenaSSOProvider.cjs +71 -47
  26. package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
  27. package/dist/auth/AthenaSSOProvider.js +71 -47
  28. package/dist/auth/AthenaSSOProvider.js.map +1 -1
  29. package/dist/auth/credential-source.cjs +120 -0
  30. package/dist/auth/credential-source.cjs.map +1 -0
  31. package/dist/auth/credential-source.d.ts +68 -0
  32. package/dist/auth/credential-source.js +120 -0
  33. package/dist/auth/credential-source.js.map +1 -0
  34. package/dist/auth/types.d.ts +9 -0
  35. package/dist/chat/AthenaChat.cjs +8 -0
  36. package/dist/chat/AthenaChat.cjs.map +1 -1
  37. package/dist/chat/AthenaChat.js +8 -0
  38. package/dist/chat/AthenaChat.js.map +1 -1
  39. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +20 -11
  40. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  41. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +11 -2
  42. package/dist/chat-ui/mentions/suggestions/data/api-client.js +20 -11
  43. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  44. package/dist/collab/mint.cjs +6 -15
  45. package/dist/collab/mint.cjs.map +1 -1
  46. package/dist/collab/mint.d.ts +8 -0
  47. package/dist/collab/mint.js +6 -15
  48. package/dist/collab/mint.js.map +1 -1
  49. package/dist/collab/presence-mint.cjs +20 -16
  50. package/dist/collab/presence-mint.cjs.map +1 -1
  51. package/dist/collab/presence-mint.js +21 -17
  52. package/dist/collab/presence-mint.js.map +1 -1
  53. package/dist/collab/presence-react.cjs +12 -5
  54. package/dist/collab/presence-react.cjs.map +1 -1
  55. package/dist/collab/presence-react.d.ts +3 -1
  56. package/dist/collab/presence-react.js +12 -5
  57. package/dist/collab/presence-react.js.map +1 -1
  58. package/dist/collab/react.cjs +5 -2
  59. package/dist/collab/react.cjs.map +1 -1
  60. package/dist/collab/react.js +5 -2
  61. package/dist/collab/react.js.map +1 -1
  62. package/dist/dictation/use-athena-dictation-engine.cjs +12 -11
  63. package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
  64. package/dist/dictation/use-athena-dictation-engine.d.ts +4 -3
  65. package/dist/dictation/use-athena-dictation-engine.js +12 -11
  66. package/dist/dictation/use-athena-dictation-engine.js.map +1 -1
  67. package/dist/index.d.ts +1 -1
  68. package/dist/packages/react/package.json.cjs +1 -1
  69. package/dist/packages/react/package.json.js +1 -1
  70. package/dist/provider/AthenaContext.cjs.map +1 -1
  71. package/dist/provider/AthenaContext.d.ts +7 -1
  72. package/dist/provider/AthenaContext.js.map +1 -1
  73. package/dist/provider/AthenaProvider.cjs +23 -2
  74. package/dist/provider/AthenaProvider.cjs.map +1 -1
  75. package/dist/provider/AthenaProvider.js +23 -2
  76. package/dist/provider/AthenaProvider.js.map +1 -1
  77. package/dist/runtime/auth-refusal-restart.cjs +66 -0
  78. package/dist/runtime/auth-refusal-restart.cjs.map +1 -0
  79. package/dist/runtime/auth-refusal-restart.d.ts +35 -0
  80. package/dist/runtime/auth-refusal-restart.js +66 -0
  81. package/dist/runtime/auth-refusal-restart.js.map +1 -0
  82. package/dist/runtime/auth.cjs +58 -21
  83. package/dist/runtime/auth.cjs.map +1 -1
  84. package/dist/runtime/auth.d.ts +11 -1
  85. package/dist/runtime/auth.js +59 -22
  86. package/dist/runtime/auth.js.map +1 -1
  87. package/dist/runtime/credential-renewal.cjs +29 -0
  88. package/dist/runtime/credential-renewal.cjs.map +1 -0
  89. package/dist/runtime/credential-renewal.d.ts +35 -0
  90. package/dist/runtime/credential-renewal.js +29 -0
  91. package/dist/runtime/credential-renewal.js.map +1 -0
  92. package/dist/search/useAthenaRepoSearch.cjs +3 -5
  93. package/dist/search/useAthenaRepoSearch.cjs.map +1 -1
  94. package/dist/search/useAthenaRepoSearch.d.ts +7 -7
  95. package/dist/search/useAthenaRepoSearch.js +3 -5
  96. package/dist/search/useAthenaRepoSearch.js.map +1 -1
  97. package/dist/threads/api.cjs +5 -1
  98. package/dist/threads/api.cjs.map +1 -1
  99. package/dist/threads/api.js +5 -1
  100. package/dist/threads/api.js.map +1 -1
  101. package/dist/threads/conversation-list-fetcher.cjs +5 -5
  102. package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
  103. package/dist/threads/conversation-list-fetcher.d.ts +6 -5
  104. package/dist/threads/conversation-list-fetcher.js +5 -5
  105. package/dist/threads/conversation-list-fetcher.js.map +1 -1
  106. package/dist/threads/statewire-thread-list.cjs +13 -14
  107. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  108. package/dist/threads/statewire-thread-list.js +13 -14
  109. package/dist/threads/statewire-thread-list.js.map +1 -1
  110. package/dist/threads/use-rest-conversation-history.cjs +6 -2
  111. package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
  112. package/dist/threads/use-rest-conversation-history.d.ts +3 -1
  113. package/dist/threads/use-rest-conversation-history.js +7 -3
  114. package/dist/threads/use-rest-conversation-history.js.map +1 -1
  115. package/dist/threads/use-statewire-conversation-history.cjs +9 -2
  116. package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
  117. package/dist/threads/use-statewire-conversation-history.d.ts +3 -1
  118. package/dist/threads/use-statewire-conversation-history.js +10 -3
  119. package/dist/threads/use-statewire-conversation-history.js.map +1 -1
  120. package/dist/threads/use-thread-archive.cjs +2 -1
  121. package/dist/threads/use-thread-archive.cjs.map +1 -1
  122. package/dist/threads/use-thread-archive.d.ts +3 -1
  123. package/dist/threads/use-thread-archive.js +2 -1
  124. package/dist/threads/use-thread-archive.js.map +1 -1
  125. package/dist/threads/use-thread-favorite.cjs.map +1 -1
  126. package/dist/threads/use-thread-favorite.d.ts +3 -1
  127. package/dist/threads/use-thread-favorite.js.map +1 -1
  128. package/dist/threads/use-thread-field-override.cjs +2 -1
  129. package/dist/threads/use-thread-field-override.cjs.map +1 -1
  130. package/dist/threads/use-thread-field-override.d.ts +3 -1
  131. package/dist/threads/use-thread-field-override.js +2 -1
  132. package/dist/threads/use-thread-field-override.js.map +1 -1
  133. package/dist/threads/use-thread-rename.cjs.map +1 -1
  134. package/dist/threads/use-thread-rename.d.ts +3 -1
  135. package/dist/threads/use-thread-rename.js.map +1 -1
  136. package/dist/tools/tool-uis.cjs +11 -15
  137. package/dist/tools/tool-uis.cjs.map +1 -1
  138. package/dist/tools/tool-uis.js +11 -15
  139. package/dist/tools/tool-uis.js.map +1 -1
  140. package/dist/voice/use-athena-voice-session.cjs +17 -5
  141. package/dist/voice/use-athena-voice-session.cjs.map +1 -1
  142. package/dist/voice/use-athena-voice-session.d.ts +2 -2
  143. package/dist/voice/use-athena-voice-session.js +17 -5
  144. package/dist/voice/use-athena-voice-session.js.map +1 -1
  145. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-source.cjs","sources":["../../src/auth/credential-source.ts"],"sourcesContent":["import type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';\n\n/**\n * Renews a token-backed sign-in. `force: true` means the token just presented\n * was refused, or has expired: the renewer must obtain a new one rather than\n * return the one it holds. Resolves `null` when it cannot produce a token.\n */\nexport type AthenaTokenRenewer = (options: { force: boolean }) => Promise<string | null>;\n\n/** What the credential source reads, fresh, on every resolve. */\nexport interface AthenaCredentialInputs {\n /**\n * The host's own getter (`config.getToken`). It owns renewal for its\n * sign-in, so it always wins; the held `token` is its fallback when it\n * resolves nothing.\n */\n hostGetToken?: AthenaStatewireTokenGetter;\n /** The token currently held: the host's, the sign-in provider's or the host bridge's. */\n token: string | null | undefined;\n /** How that token renews (the sign-in provider or the host bridge); absent for a static token. */\n renew?: AthenaTokenRenewer;\n}\n\n/**\n * The single place every SDK network path gets the token it presents — the\n * live thread connection, the session list's index and REST calls, uploads,\n * search, voice and the collaborative-document mint — read right before it is\n * presented.\n */\nexport interface AthenaCredentialSource {\n /**\n * The token to present now. `force` renews it first (the previous one was\n * refused). A token that has expired, or expires within\n * {@link TOKEN_EXPIRY_SKEW_MS}, is renewed before it is presented, so a tab\n * waking from sleep never presents a dead token. Concurrent renewals share\n * one in-flight request, and calls made while one is in flight wait for it\n * instead of presenting the token it is replacing. A renewal never hands one\n * account's token to a call made after the signed-in account changed.\n */\n getToken: (options?: { force?: boolean }) => Promise<string | null>;\n /** Called, with no arguments, whenever a different token becomes current. */\n subscribe: (listener: () => void) => () => void;\n /**\n * How many times the identity behind the token has changed: its JWT\n * subject, or the token itself when it is opaque. Renewals for the same\n * identity leave it alone. Long-lived connections key on it, so they keep\n * running across renewals and are rebuilt when someone else signs in,\n * including under a host `getToken`, whose identity is only known once a\n * token has been resolved. Subscribers hear when it moves.\n */\n identityEpoch: () => number;\n /** Tell subscribers the held token changed (the provider calls this when its inputs do). */\n notifyTokenChanged: () => void;\n}\n\n/** A token this close to its expiry is renewed before it is presented. */\nexport const TOKEN_EXPIRY_SKEW_MS = 30_000;\n\n/**\n * The `exp` of a JWT, in milliseconds, or `null` for anything that is not a\n * JWT with a numeric `exp`. Read without verification: it only decides whether\n * to renew before presenting; the server still validates every token.\n */\nexport function jwtExpiresAtMs(token: string): number | null {\n const payload = token.split('.')[1];\n if (!payload) return null;\n try {\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const exp: unknown = (JSON.parse(atob(padded)) as { exp?: unknown }).exp;\n return typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\n/** The unverified `sub` of a JWT, or `null` for anything that is not a JWT with one. */\nexport function jwtSubject(token: string): string | null {\n const payload = token.split('.')[1];\n if (!payload) return null;\n try {\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const sub: unknown = (JSON.parse(atob(padded)) as { sub?: unknown }).sub;\n return typeof sub === 'string' && sub.length > 0 ? sub : null;\n } catch {\n return null;\n }\n}\n\n/** True for a JWT that has expired or expires within {@link TOKEN_EXPIRY_SKEW_MS}. */\nexport function isTokenExpiring(token: string, now: number = Date.now()): boolean {\n const expiresAt = jwtExpiresAtMs(token);\n return expiresAt !== null && expiresAt - now <= TOKEN_EXPIRY_SKEW_MS;\n}\n\nexport function createAthenaCredentialSource(\n read: () => AthenaCredentialInputs,\n): AthenaCredentialSource {\n const listeners = new Set<() => void>();\n // The renewal in flight, and whether the host's getter runs it (the host\n // owns identity for its getter) or the sign-in provider's / bridge's renewer.\n let renewal: { token: Promise<string | null>; byHost: boolean } | null = null;\n let lastResolved: string | null = null;\n let identity: string | null = null;\n let identityEpoch = 0;\n\n const notifyListeners = () => {\n for (const listener of [...listeners]) listener();\n };\n\n /** Note who a token acts as; true when that is someone other than before. */\n const observeIdentity = (token: string | null | undefined): boolean => {\n if (!token) return false;\n const next = jwtSubject(token) ?? token;\n if (next === identity) return false;\n const changed = identity !== null;\n identity = next;\n if (changed) identityEpoch += 1;\n return changed;\n };\n\n const notifyTokenChanged = () => {\n observeIdentity(read().token);\n notifyListeners();\n };\n\n /** Record what a resolve produced; a different token than the last one is news. */\n const settle = (token: string | null): string | null => {\n const identityChanged = observeIdentity(token);\n if (token !== null && token !== lastResolved) {\n const replaced = lastResolved !== null;\n lastResolved = token;\n if (replaced || identityChanged) notifyListeners();\n } else if (identityChanged) {\n notifyListeners();\n }\n return token;\n };\n\n const shareRenewal = (\n start: () => Promise<string | null>,\n byHost: boolean,\n ): { token: Promise<string | null>; byHost: boolean } => {\n if (!renewal) {\n const entry = {\n token: start().finally(() => {\n if (renewal === entry) renewal = null;\n }),\n byHost,\n };\n renewal = entry;\n }\n return renewal;\n };\n\n /**\n * What a finished renewal hands one caller. A host getter's token is\n * presented as is: the host owns identity for its getter. A sign-in\n * provider's or bridge's renewed token is presented only while it acts as\n * the account the provider holds now. When the account changed while the\n * renewal was in flight (its JWT subject differs from the held token's, or\n * the provider holds no token any more), the held token, the current\n * account's, is presented instead. A renewal that produced nothing keeps\n * the held token: the caller presents it and the host's refusal ends the\n * attempt.\n */\n const presentable = (\n { byHost }: { byHost: boolean },\n renewed: string | null,\n ): string | null => {\n const held = read().token ?? null;\n if (byHost) return renewed ?? held;\n if (!renewed || !held) return held;\n const heldSubject = jwtSubject(held);\n const renewedSubject = jwtSubject(renewed);\n return heldSubject && renewedSubject && heldSubject !== renewedSubject ? held : renewed;\n };\n\n const awaitRenewal = async (shared: {\n token: Promise<string | null>;\n byHost: boolean;\n }): Promise<string | null> => settle(presentable(shared, await shared.token));\n\n const getToken = async ({ force = false }: { force?: boolean } = {}): Promise<string | null> => {\n if (renewal) return awaitRenewal(renewal);\n const inputs = read();\n const hostGetToken = inputs.hostGetToken;\n if (hostGetToken) {\n if (!force) return settle((await hostGetToken({ force: false })) ?? read().token ?? null);\n return awaitRenewal(\n shareRenewal(async () => (await hostGetToken({ force: true })) ?? null, true),\n );\n }\n const current = inputs.token ?? null;\n const renew = inputs.renew;\n if (!renew) return settle(current);\n const stale = force || (current !== null && isTokenExpiring(current));\n if (!stale) return settle(current);\n return awaitRenewal(shareRenewal(() => renew({ force: true }), false));\n };\n\n return {\n getToken,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n notifyTokenChanged,\n identityEpoch: () => identityEpoch,\n };\n}\n"],"names":[],"mappings":";;AAwDO,MAAM,uBAAuB;AAO7B,SAAS,eAAe,OAA8B;AAC3D,QAAM,UAAU,MAAM,MAAM,GAAG,EAAE,CAAC;AAClC,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,UAAM,SAAS,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAC3D,UAAM,SAAS,OAAO,OAAO,KAAK,KAAK,OAAO,SAAS,CAAC,IAAI,GAAG,GAAG;AAClE,UAAM,MAAgB,KAAK,MAAM,KAAK,MAAM,CAAC,EAAwB;AACrE,WAAO,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG,IAAI,MAAM,MAAO;AAAA,EACxE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,WAAW,OAA8B;AACvD,QAAM,UAAU,MAAM,MAAM,GAAG,EAAE,CAAC;AAClC,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,UAAM,SAAS,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAC3D,UAAM,SAAS,OAAO,OAAO,KAAK,KAAK,OAAO,SAAS,CAAC,IAAI,GAAG,GAAG;AAClE,UAAM,MAAgB,KAAK,MAAM,KAAK,MAAM,CAAC,EAAwB;AACrE,WAAO,OAAO,QAAQ,YAAY,IAAI,SAAS,IAAI,MAAM;AAAA,EAC3D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,gBAAgB,OAAe,MAAc,KAAK,OAAgB;AAChF,QAAM,YAAY,eAAe,KAAK;AACtC,SAAO,cAAc,QAAQ,YAAY,OAAO;AAClD;AAEO,SAAS,6BACd,MACwB;AACxB,QAAM,gCAAgB,IAAA;AAGtB,MAAI,UAAqE;AACzE,MAAI,eAA8B;AAClC,MAAI,WAA0B;AAC9B,MAAI,gBAAgB;AAEpB,QAAM,kBAAkB,MAAM;AAC5B,eAAW,YAAY,CAAC,GAAG,SAAS,EAAG,UAAA;AAAA,EACzC;AAGA,QAAM,kBAAkB,CAAC,UAA8C;AACrE,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,OAAO,WAAW,KAAK,KAAK;AAClC,QAAI,SAAS,SAAU,QAAO;AAC9B,UAAM,UAAU,aAAa;AAC7B,eAAW;AACX,QAAI,QAAS,kBAAiB;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,MAAM;AAC/B,oBAAgB,KAAA,EAAO,KAAK;AAC5B,oBAAA;AAAA,EACF;AAGA,QAAM,SAAS,CAAC,UAAwC;AACtD,UAAM,kBAAkB,gBAAgB,KAAK;AAC7C,QAAI,UAAU,QAAQ,UAAU,cAAc;AAC5C,YAAM,WAAW,iBAAiB;AAClC,qBAAe;AACf,UAAI,YAAY,gBAAiB,iBAAA;AAAA,IACnC,WAAW,iBAAiB;AAC1B,sBAAA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,CACnB,OACA,WACuD;AACvD,QAAI,CAAC,SAAS;AACZ,YAAM,QAAQ;AAAA,QACZ,OAAO,QAAQ,QAAQ,MAAM;AAC3B,cAAI,YAAY,MAAO,WAAU;AAAA,QACnC,CAAC;AAAA,QACD;AAAA,MAAA;AAEF,gBAAU;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAaA,QAAM,cAAc,CAClB,EAAE,OAAA,GACF,YACkB;AAClB,UAAM,OAAO,OAAO,SAAS;AAC7B,QAAI,eAAe,WAAW;AAC9B,QAAI,CAAC,WAAW,CAAC,KAAM,QAAO;AAC9B,UAAM,cAAc,WAAW,IAAI;AACnC,UAAM,iBAAiB,WAAW,OAAO;AACzC,WAAO,eAAe,kBAAkB,gBAAgB,iBAAiB,OAAO;AAAA,EAClF;AAEA,QAAM,eAAe,OAAO,WAGE,OAAO,YAAY,QAAQ,MAAM,OAAO,KAAK,CAAC;AAE5E,QAAM,WAAW,OAAO,EAAE,QAAQ,MAAA,IAA+B,CAAA,MAA+B;AAC9F,QAAI,QAAS,QAAO,aAAa,OAAO;AACxC,UAAM,SAAS,KAAA;AACf,UAAM,eAAe,OAAO;AAC5B,QAAI,cAAc;AAChB,UAAI,CAAC,MAAO,QAAO,OAAQ,MAAM,aAAa,EAAE,OAAO,MAAA,CAAO,KAAM,OAAO,SAAS,IAAI;AACxF,aAAO;AAAA,QACL,aAAa,YAAa,MAAM,aAAa,EAAE,OAAO,KAAA,CAAM,KAAM,MAAM,IAAI;AAAA,MAAA;AAAA,IAEhF;AACA,UAAM,UAAU,OAAO,SAAS;AAChC,UAAM,QAAQ,OAAO;AACrB,QAAI,CAAC,MAAO,QAAO,OAAO,OAAO;AACjC,UAAM,QAAQ,SAAU,YAAY,QAAQ,gBAAgB,OAAO;AACnE,QAAI,CAAC,MAAO,QAAO,OAAO,OAAO;AACjC,WAAO,aAAa,aAAa,MAAM,MAAM,EAAE,OAAO,KAAA,CAAM,GAAG,KAAK,CAAC;AAAA,EACvE;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,CAAC,aAAa;AACvB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,IACA;AAAA,IACA,eAAe,MAAM;AAAA,EAAA;AAEzB;;;;;;"}
@@ -0,0 +1,68 @@
1
+ import type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';
2
+ /**
3
+ * Renews a token-backed sign-in. `force: true` means the token just presented
4
+ * was refused, or has expired: the renewer must obtain a new one rather than
5
+ * return the one it holds. Resolves `null` when it cannot produce a token.
6
+ */
7
+ export type AthenaTokenRenewer = (options: {
8
+ force: boolean;
9
+ }) => Promise<string | null>;
10
+ /** What the credential source reads, fresh, on every resolve. */
11
+ export interface AthenaCredentialInputs {
12
+ /**
13
+ * The host's own getter (`config.getToken`). It owns renewal for its
14
+ * sign-in, so it always wins; the held `token` is its fallback when it
15
+ * resolves nothing.
16
+ */
17
+ hostGetToken?: AthenaStatewireTokenGetter;
18
+ /** The token currently held: the host's, the sign-in provider's or the host bridge's. */
19
+ token: string | null | undefined;
20
+ /** How that token renews (the sign-in provider or the host bridge); absent for a static token. */
21
+ renew?: AthenaTokenRenewer;
22
+ }
23
+ /**
24
+ * The single place every SDK network path gets the token it presents — the
25
+ * live thread connection, the session list's index and REST calls, uploads,
26
+ * search, voice and the collaborative-document mint — read right before it is
27
+ * presented.
28
+ */
29
+ export interface AthenaCredentialSource {
30
+ /**
31
+ * The token to present now. `force` renews it first (the previous one was
32
+ * refused). A token that has expired, or expires within
33
+ * {@link TOKEN_EXPIRY_SKEW_MS}, is renewed before it is presented, so a tab
34
+ * waking from sleep never presents a dead token. Concurrent renewals share
35
+ * one in-flight request, and calls made while one is in flight wait for it
36
+ * instead of presenting the token it is replacing. A renewal never hands one
37
+ * account's token to a call made after the signed-in account changed.
38
+ */
39
+ getToken: (options?: {
40
+ force?: boolean;
41
+ }) => Promise<string | null>;
42
+ /** Called, with no arguments, whenever a different token becomes current. */
43
+ subscribe: (listener: () => void) => () => void;
44
+ /**
45
+ * How many times the identity behind the token has changed: its JWT
46
+ * subject, or the token itself when it is opaque. Renewals for the same
47
+ * identity leave it alone. Long-lived connections key on it, so they keep
48
+ * running across renewals and are rebuilt when someone else signs in,
49
+ * including under a host `getToken`, whose identity is only known once a
50
+ * token has been resolved. Subscribers hear when it moves.
51
+ */
52
+ identityEpoch: () => number;
53
+ /** Tell subscribers the held token changed (the provider calls this when its inputs do). */
54
+ notifyTokenChanged: () => void;
55
+ }
56
+ /** A token this close to its expiry is renewed before it is presented. */
57
+ export declare const TOKEN_EXPIRY_SKEW_MS = 30000;
58
+ /**
59
+ * The `exp` of a JWT, in milliseconds, or `null` for anything that is not a
60
+ * JWT with a numeric `exp`. Read without verification: it only decides whether
61
+ * to renew before presenting; the server still validates every token.
62
+ */
63
+ export declare function jwtExpiresAtMs(token: string): number | null;
64
+ /** The unverified `sub` of a JWT, or `null` for anything that is not a JWT with one. */
65
+ export declare function jwtSubject(token: string): string | null;
66
+ /** True for a JWT that has expired or expires within {@link TOKEN_EXPIRY_SKEW_MS}. */
67
+ export declare function isTokenExpiring(token: string, now?: number): boolean;
68
+ export declare function createAthenaCredentialSource(read: () => AthenaCredentialInputs): AthenaCredentialSource;
@@ -0,0 +1,120 @@
1
+ const TOKEN_EXPIRY_SKEW_MS = 3e4;
2
+ function jwtExpiresAtMs(token) {
3
+ const payload = token.split(".")[1];
4
+ if (!payload) return null;
5
+ try {
6
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
7
+ const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
8
+ const exp = JSON.parse(atob(padded)).exp;
9
+ return typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : null;
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+ function jwtSubject(token) {
15
+ const payload = token.split(".")[1];
16
+ if (!payload) return null;
17
+ try {
18
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
19
+ const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
20
+ const sub = JSON.parse(atob(padded)).sub;
21
+ return typeof sub === "string" && sub.length > 0 ? sub : null;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ function isTokenExpiring(token, now = Date.now()) {
27
+ const expiresAt = jwtExpiresAtMs(token);
28
+ return expiresAt !== null && expiresAt - now <= TOKEN_EXPIRY_SKEW_MS;
29
+ }
30
+ function createAthenaCredentialSource(read) {
31
+ const listeners = /* @__PURE__ */ new Set();
32
+ let renewal = null;
33
+ let lastResolved = null;
34
+ let identity = null;
35
+ let identityEpoch = 0;
36
+ const notifyListeners = () => {
37
+ for (const listener of [...listeners]) listener();
38
+ };
39
+ const observeIdentity = (token) => {
40
+ if (!token) return false;
41
+ const next = jwtSubject(token) ?? token;
42
+ if (next === identity) return false;
43
+ const changed = identity !== null;
44
+ identity = next;
45
+ if (changed) identityEpoch += 1;
46
+ return changed;
47
+ };
48
+ const notifyTokenChanged = () => {
49
+ observeIdentity(read().token);
50
+ notifyListeners();
51
+ };
52
+ const settle = (token) => {
53
+ const identityChanged = observeIdentity(token);
54
+ if (token !== null && token !== lastResolved) {
55
+ const replaced = lastResolved !== null;
56
+ lastResolved = token;
57
+ if (replaced || identityChanged) notifyListeners();
58
+ } else if (identityChanged) {
59
+ notifyListeners();
60
+ }
61
+ return token;
62
+ };
63
+ const shareRenewal = (start, byHost) => {
64
+ if (!renewal) {
65
+ const entry = {
66
+ token: start().finally(() => {
67
+ if (renewal === entry) renewal = null;
68
+ }),
69
+ byHost
70
+ };
71
+ renewal = entry;
72
+ }
73
+ return renewal;
74
+ };
75
+ const presentable = ({ byHost }, renewed) => {
76
+ const held = read().token ?? null;
77
+ if (byHost) return renewed ?? held;
78
+ if (!renewed || !held) return held;
79
+ const heldSubject = jwtSubject(held);
80
+ const renewedSubject = jwtSubject(renewed);
81
+ return heldSubject && renewedSubject && heldSubject !== renewedSubject ? held : renewed;
82
+ };
83
+ const awaitRenewal = async (shared) => settle(presentable(shared, await shared.token));
84
+ const getToken = async ({ force = false } = {}) => {
85
+ if (renewal) return awaitRenewal(renewal);
86
+ const inputs = read();
87
+ const hostGetToken = inputs.hostGetToken;
88
+ if (hostGetToken) {
89
+ if (!force) return settle(await hostGetToken({ force: false }) ?? read().token ?? null);
90
+ return awaitRenewal(
91
+ shareRenewal(async () => await hostGetToken({ force: true }) ?? null, true)
92
+ );
93
+ }
94
+ const current = inputs.token ?? null;
95
+ const renew = inputs.renew;
96
+ if (!renew) return settle(current);
97
+ const stale = force || current !== null && isTokenExpiring(current);
98
+ if (!stale) return settle(current);
99
+ return awaitRenewal(shareRenewal(() => renew({ force: true }), false));
100
+ };
101
+ return {
102
+ getToken,
103
+ subscribe: (listener) => {
104
+ listeners.add(listener);
105
+ return () => {
106
+ listeners.delete(listener);
107
+ };
108
+ },
109
+ notifyTokenChanged,
110
+ identityEpoch: () => identityEpoch
111
+ };
112
+ }
113
+ export {
114
+ TOKEN_EXPIRY_SKEW_MS,
115
+ createAthenaCredentialSource,
116
+ isTokenExpiring,
117
+ jwtExpiresAtMs,
118
+ jwtSubject
119
+ };
120
+ //# sourceMappingURL=credential-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-source.js","sources":["../../src/auth/credential-source.ts"],"sourcesContent":["import type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';\n\n/**\n * Renews a token-backed sign-in. `force: true` means the token just presented\n * was refused, or has expired: the renewer must obtain a new one rather than\n * return the one it holds. Resolves `null` when it cannot produce a token.\n */\nexport type AthenaTokenRenewer = (options: { force: boolean }) => Promise<string | null>;\n\n/** What the credential source reads, fresh, on every resolve. */\nexport interface AthenaCredentialInputs {\n /**\n * The host's own getter (`config.getToken`). It owns renewal for its\n * sign-in, so it always wins; the held `token` is its fallback when it\n * resolves nothing.\n */\n hostGetToken?: AthenaStatewireTokenGetter;\n /** The token currently held: the host's, the sign-in provider's or the host bridge's. */\n token: string | null | undefined;\n /** How that token renews (the sign-in provider or the host bridge); absent for a static token. */\n renew?: AthenaTokenRenewer;\n}\n\n/**\n * The single place every SDK network path gets the token it presents — the\n * live thread connection, the session list's index and REST calls, uploads,\n * search, voice and the collaborative-document mint — read right before it is\n * presented.\n */\nexport interface AthenaCredentialSource {\n /**\n * The token to present now. `force` renews it first (the previous one was\n * refused). A token that has expired, or expires within\n * {@link TOKEN_EXPIRY_SKEW_MS}, is renewed before it is presented, so a tab\n * waking from sleep never presents a dead token. Concurrent renewals share\n * one in-flight request, and calls made while one is in flight wait for it\n * instead of presenting the token it is replacing. A renewal never hands one\n * account's token to a call made after the signed-in account changed.\n */\n getToken: (options?: { force?: boolean }) => Promise<string | null>;\n /** Called, with no arguments, whenever a different token becomes current. */\n subscribe: (listener: () => void) => () => void;\n /**\n * How many times the identity behind the token has changed: its JWT\n * subject, or the token itself when it is opaque. Renewals for the same\n * identity leave it alone. Long-lived connections key on it, so they keep\n * running across renewals and are rebuilt when someone else signs in,\n * including under a host `getToken`, whose identity is only known once a\n * token has been resolved. Subscribers hear when it moves.\n */\n identityEpoch: () => number;\n /** Tell subscribers the held token changed (the provider calls this when its inputs do). */\n notifyTokenChanged: () => void;\n}\n\n/** A token this close to its expiry is renewed before it is presented. */\nexport const TOKEN_EXPIRY_SKEW_MS = 30_000;\n\n/**\n * The `exp` of a JWT, in milliseconds, or `null` for anything that is not a\n * JWT with a numeric `exp`. Read without verification: it only decides whether\n * to renew before presenting; the server still validates every token.\n */\nexport function jwtExpiresAtMs(token: string): number | null {\n const payload = token.split('.')[1];\n if (!payload) return null;\n try {\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const exp: unknown = (JSON.parse(atob(padded)) as { exp?: unknown }).exp;\n return typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\n/** The unverified `sub` of a JWT, or `null` for anything that is not a JWT with one. */\nexport function jwtSubject(token: string): string | null {\n const payload = token.split('.')[1];\n if (!payload) return null;\n try {\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const sub: unknown = (JSON.parse(atob(padded)) as { sub?: unknown }).sub;\n return typeof sub === 'string' && sub.length > 0 ? sub : null;\n } catch {\n return null;\n }\n}\n\n/** True for a JWT that has expired or expires within {@link TOKEN_EXPIRY_SKEW_MS}. */\nexport function isTokenExpiring(token: string, now: number = Date.now()): boolean {\n const expiresAt = jwtExpiresAtMs(token);\n return expiresAt !== null && expiresAt - now <= TOKEN_EXPIRY_SKEW_MS;\n}\n\nexport function createAthenaCredentialSource(\n read: () => AthenaCredentialInputs,\n): AthenaCredentialSource {\n const listeners = new Set<() => void>();\n // The renewal in flight, and whether the host's getter runs it (the host\n // owns identity for its getter) or the sign-in provider's / bridge's renewer.\n let renewal: { token: Promise<string | null>; byHost: boolean } | null = null;\n let lastResolved: string | null = null;\n let identity: string | null = null;\n let identityEpoch = 0;\n\n const notifyListeners = () => {\n for (const listener of [...listeners]) listener();\n };\n\n /** Note who a token acts as; true when that is someone other than before. */\n const observeIdentity = (token: string | null | undefined): boolean => {\n if (!token) return false;\n const next = jwtSubject(token) ?? token;\n if (next === identity) return false;\n const changed = identity !== null;\n identity = next;\n if (changed) identityEpoch += 1;\n return changed;\n };\n\n const notifyTokenChanged = () => {\n observeIdentity(read().token);\n notifyListeners();\n };\n\n /** Record what a resolve produced; a different token than the last one is news. */\n const settle = (token: string | null): string | null => {\n const identityChanged = observeIdentity(token);\n if (token !== null && token !== lastResolved) {\n const replaced = lastResolved !== null;\n lastResolved = token;\n if (replaced || identityChanged) notifyListeners();\n } else if (identityChanged) {\n notifyListeners();\n }\n return token;\n };\n\n const shareRenewal = (\n start: () => Promise<string | null>,\n byHost: boolean,\n ): { token: Promise<string | null>; byHost: boolean } => {\n if (!renewal) {\n const entry = {\n token: start().finally(() => {\n if (renewal === entry) renewal = null;\n }),\n byHost,\n };\n renewal = entry;\n }\n return renewal;\n };\n\n /**\n * What a finished renewal hands one caller. A host getter's token is\n * presented as is: the host owns identity for its getter. A sign-in\n * provider's or bridge's renewed token is presented only while it acts as\n * the account the provider holds now. When the account changed while the\n * renewal was in flight (its JWT subject differs from the held token's, or\n * the provider holds no token any more), the held token, the current\n * account's, is presented instead. A renewal that produced nothing keeps\n * the held token: the caller presents it and the host's refusal ends the\n * attempt.\n */\n const presentable = (\n { byHost }: { byHost: boolean },\n renewed: string | null,\n ): string | null => {\n const held = read().token ?? null;\n if (byHost) return renewed ?? held;\n if (!renewed || !held) return held;\n const heldSubject = jwtSubject(held);\n const renewedSubject = jwtSubject(renewed);\n return heldSubject && renewedSubject && heldSubject !== renewedSubject ? held : renewed;\n };\n\n const awaitRenewal = async (shared: {\n token: Promise<string | null>;\n byHost: boolean;\n }): Promise<string | null> => settle(presentable(shared, await shared.token));\n\n const getToken = async ({ force = false }: { force?: boolean } = {}): Promise<string | null> => {\n if (renewal) return awaitRenewal(renewal);\n const inputs = read();\n const hostGetToken = inputs.hostGetToken;\n if (hostGetToken) {\n if (!force) return settle((await hostGetToken({ force: false })) ?? read().token ?? null);\n return awaitRenewal(\n shareRenewal(async () => (await hostGetToken({ force: true })) ?? null, true),\n );\n }\n const current = inputs.token ?? null;\n const renew = inputs.renew;\n if (!renew) return settle(current);\n const stale = force || (current !== null && isTokenExpiring(current));\n if (!stale) return settle(current);\n return awaitRenewal(shareRenewal(() => renew({ force: true }), false));\n };\n\n return {\n getToken,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n notifyTokenChanged,\n identityEpoch: () => identityEpoch,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';
1
2
  /**
2
3
  * Athena user information — a simplified, PropelAuth-agnostic representation.
3
4
  */
@@ -63,4 +64,12 @@ export interface AthenaAuthState {
63
64
  orgs: AthenaOrg[];
64
65
  /** Log the user out. Redirects to the login page by default. */
65
66
  logout: (redirectOnLogout?: boolean) => Promise<void>;
67
+ /**
68
+ * Resolve a current access token, renewing it when it is about to expire.
69
+ * `{ force: true }` means the previous token was refused: renew it first.
70
+ * `AthenaAuthProvider` and `AthenaSSOProvider` supply it, and
71
+ * `AthenaProvider` uses it for every request and reconnect. A custom
72
+ * provider may omit it; `accessToken` is then used as it is.
73
+ */
74
+ getToken?: AthenaStatewireTokenGetter;
66
75
  }
@@ -151,6 +151,14 @@ const AthenaChat = ({
151
151
  credentials: "include",
152
152
  get accessToken() {
153
153
  return athenaConfig.token ?? void 0;
154
+ },
155
+ getAccessToken: async () => {
156
+ var _a2;
157
+ return await ((_a2 = athenaConfig.getToken) == null ? void 0 : _a2.call(athenaConfig)) ?? void 0;
158
+ },
159
+ renewAccessToken: async () => {
160
+ var _a2;
161
+ return await ((_a2 = athenaConfig.getToken) == null ? void 0 : _a2.call(athenaConfig, { force: true })) ?? void 0;
154
162
  }
155
163
  }),
156
164
  [athenaConfig]