@tiledev/sdk-apptile-live-selling 0.16.0 → 0.16.1

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 (410) hide show
  1. package/dist/attribution.d.ts +2 -16
  2. package/dist/attribution.d.ts.map +1 -1
  3. package/dist/attribution.js +4 -10
  4. package/dist/attribution.js.map +1 -1
  5. package/dist/auctions.d.ts.map +1 -1
  6. package/dist/auctions.js +11 -42
  7. package/dist/auctions.js.map +1 -1
  8. package/dist/cartAttributes.d.ts +0 -10
  9. package/dist/cartAttributes.d.ts.map +1 -1
  10. package/dist/cartAttributes.js +1 -20
  11. package/dist/cartAttributes.js.map +1 -1
  12. package/dist/client.d.ts +2 -51
  13. package/dist/client.d.ts.map +1 -1
  14. package/dist/client.js +23 -123
  15. package/dist/client.js.map +1 -1
  16. package/dist/clips.d.ts +1 -12
  17. package/dist/clips.d.ts.map +1 -1
  18. package/dist/clips.js +6 -114
  19. package/dist/clips.js.map +1 -1
  20. package/dist/commentLinks.d.ts +0 -29
  21. package/dist/commentLinks.d.ts.map +1 -1
  22. package/dist/commentLinks.js.map +1 -1
  23. package/dist/engine.native.d.ts.map +1 -1
  24. package/dist/engine.native.js +845 -17
  25. package/dist/engine.native.js.map +1 -1
  26. package/dist/index.d.ts +4 -48
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3 -240
  29. package/dist/index.js.map +1 -1
  30. package/dist/polls.d.ts.map +1 -1
  31. package/dist/polls.js +0 -3
  32. package/dist/polls.js.map +1 -1
  33. package/dist/react/LiveSellingProvider.d.ts +1 -54
  34. package/dist/react/LiveSellingProvider.d.ts.map +1 -1
  35. package/dist/react/LiveSellingProvider.js +3 -60
  36. package/dist/react/LiveSellingProvider.js.map +1 -1
  37. package/dist/react/LiveVideoTarget.d.ts.map +1 -1
  38. package/dist/react/LiveVideoTarget.js +3 -41
  39. package/dist/react/LiveVideoTarget.js.map +1 -1
  40. package/dist/react/index.d.ts +3 -30
  41. package/dist/react/index.d.ts.map +1 -1
  42. package/dist/react/index.js +1 -79
  43. package/dist/react/index.js.map +1 -1
  44. package/dist/react/index.web.d.ts +32 -36
  45. package/dist/react/index.web.d.ts.map +1 -1
  46. package/dist/react/index.web.js +122 -102
  47. package/dist/react/index.web.js.map +1 -1
  48. package/dist/react/useAuctionBidGate.d.ts +6 -62
  49. package/dist/react/useAuctionBidGate.d.ts.map +1 -1
  50. package/dist/react/useAuctionBidGate.js +27 -228
  51. package/dist/react/useAuctionBidGate.js.map +1 -1
  52. package/dist/react/useAuctionWins.d.ts +4 -14
  53. package/dist/react/useAuctionWins.d.ts.map +1 -1
  54. package/dist/react/useAuctionWins.js +5 -16
  55. package/dist/react/useAuctionWins.js.map +1 -1
  56. package/dist/react/useClips.d.ts +1 -7
  57. package/dist/react/useClips.d.ts.map +1 -1
  58. package/dist/react/useClips.js +7 -20
  59. package/dist/react/useClips.js.map +1 -1
  60. package/dist/react/useLiveSession.d.ts +3 -15
  61. package/dist/react/useLiveSession.d.ts.map +1 -1
  62. package/dist/react/useLiveSession.js +199 -612
  63. package/dist/react/useLiveSession.js.map +1 -1
  64. package/dist/react/useLiveStreams.d.ts.map +1 -1
  65. package/dist/react/useLiveStreams.js +2 -6
  66. package/dist/react/useLiveStreams.js.map +1 -1
  67. package/dist/react/useOngoingLive.d.ts +0 -1
  68. package/dist/react/useOngoingLive.d.ts.map +1 -1
  69. package/dist/react/useOngoingLive.js +1 -7
  70. package/dist/react/useOngoingLive.js.map +1 -1
  71. package/dist/react/useReplays.d.ts +0 -12
  72. package/dist/react/useReplays.d.ts.map +1 -1
  73. package/dist/react/useReplays.js +24 -56
  74. package/dist/react/useReplays.js.map +1 -1
  75. package/dist/react/useStreamInfo.d.ts +2 -13
  76. package/dist/react/useStreamInfo.d.ts.map +1 -1
  77. package/dist/react/useStreamInfo.js +8 -36
  78. package/dist/react/useStreamInfo.js.map +1 -1
  79. package/dist/replays.d.ts +0 -14
  80. package/dist/replays.d.ts.map +1 -1
  81. package/dist/replays.js +22 -68
  82. package/dist/replays.js.map +1 -1
  83. package/dist/session.d.ts +6 -39
  84. package/dist/session.d.ts.map +1 -1
  85. package/dist/session.js +22 -209
  86. package/dist/session.js.map +1 -1
  87. package/dist/sessionTypes.d.ts +18 -217
  88. package/dist/sessionTypes.d.ts.map +1 -1
  89. package/dist/sessionTypes.js +1 -2
  90. package/dist/sessionTypes.js.map +1 -1
  91. package/dist/streams.d.ts +1 -27
  92. package/dist/streams.d.ts.map +1 -1
  93. package/dist/streams.js +21 -84
  94. package/dist/streams.js.map +1 -1
  95. package/dist/types.d.ts +10 -288
  96. package/dist/types.d.ts.map +1 -1
  97. package/dist/types.js +1 -2
  98. package/dist/types.js.map +1 -1
  99. package/dist/wire.d.ts +0 -31
  100. package/dist/wire.d.ts.map +1 -1
  101. package/dist/wire.js +0 -25
  102. package/dist/wire.js.map +1 -1
  103. package/dist/zego.d.ts +1 -3
  104. package/dist/zego.d.ts.map +1 -1
  105. package/dist/zego.js +1 -1
  106. package/package.json +1 -1
  107. package/dist/auctionComments.d.ts +0 -25
  108. package/dist/auctionComments.d.ts.map +0 -1
  109. package/dist/auctionComments.js +0 -28
  110. package/dist/auctionComments.js.map +0 -1
  111. package/dist/auctionRules.d.ts +0 -77
  112. package/dist/auctionRules.d.ts.map +0 -1
  113. package/dist/auctionRules.js +0 -107
  114. package/dist/auctionRules.js.map +0 -1
  115. package/dist/cartExtension.d.ts +0 -39
  116. package/dist/cartExtension.d.ts.map +0 -1
  117. package/dist/cartExtension.js +0 -51
  118. package/dist/cartExtension.js.map +0 -1
  119. package/dist/checkoutRefused.d.ts +0 -9
  120. package/dist/checkoutRefused.d.ts.map +0 -1
  121. package/dist/checkoutRefused.js +0 -16
  122. package/dist/checkoutRefused.js.map +0 -1
  123. package/dist/clipsPage.d.ts +0 -29
  124. package/dist/clipsPage.d.ts.map +0 -1
  125. package/dist/clipsPage.js +0 -49
  126. package/dist/clipsPage.js.map +0 -1
  127. package/dist/commentHistory.d.ts +0 -70
  128. package/dist/commentHistory.d.ts.map +0 -1
  129. package/dist/commentHistory.js +0 -133
  130. package/dist/commentHistory.js.map +0 -1
  131. package/dist/commentLinkCards.d.ts +0 -11
  132. package/dist/commentLinkCards.d.ts.map +0 -1
  133. package/dist/commentLinkCards.js +0 -70
  134. package/dist/commentLinkCards.js.map +0 -1
  135. package/dist/giveawayPrize.d.ts +0 -13
  136. package/dist/giveawayPrize.d.ts.map +0 -1
  137. package/dist/giveawayPrize.js +0 -18
  138. package/dist/giveawayPrize.js.map +0 -1
  139. package/dist/giveawayPrizeLines.d.ts +0 -120
  140. package/dist/giveawayPrizeLines.d.ts.map +0 -1
  141. package/dist/giveawayPrizeLines.js +0 -97
  142. package/dist/giveawayPrizeLines.js.map +0 -1
  143. package/dist/giveawayPrizes.d.ts +0 -20
  144. package/dist/giveawayPrizes.d.ts.map +0 -1
  145. package/dist/giveawayPrizes.js +0 -50
  146. package/dist/giveawayPrizes.js.map +0 -1
  147. package/dist/giveawayRoster.d.ts +0 -53
  148. package/dist/giveawayRoster.d.ts.map +0 -1
  149. package/dist/giveawayRoster.js +0 -93
  150. package/dist/giveawayRoster.js.map +0 -1
  151. package/dist/heldComments.d.ts +0 -40
  152. package/dist/heldComments.d.ts.map +0 -1
  153. package/dist/heldComments.js +0 -75
  154. package/dist/heldComments.js.map +0 -1
  155. package/dist/hiddenShows.d.ts +0 -44
  156. package/dist/hiddenShows.d.ts.map +0 -1
  157. package/dist/hiddenShows.js +0 -53
  158. package/dist/hiddenShows.js.map +0 -1
  159. package/dist/linkLots.d.ts +0 -64
  160. package/dist/linkLots.d.ts.map +0 -1
  161. package/dist/linkLots.js +0 -84
  162. package/dist/linkLots.js.map +0 -1
  163. package/dist/liveHaptics.d.ts +0 -7
  164. package/dist/liveHaptics.d.ts.map +0 -1
  165. package/dist/liveHaptics.js +0 -11
  166. package/dist/liveHaptics.js.map +0 -1
  167. package/dist/liveHaptics.native.d.ts +0 -7
  168. package/dist/liveHaptics.native.d.ts.map +0 -1
  169. package/dist/liveHaptics.native.js +0 -12
  170. package/dist/liveHaptics.native.js.map +0 -1
  171. package/dist/livePages.d.ts +0 -176
  172. package/dist/livePages.d.ts.map +0 -1
  173. package/dist/livePages.js +0 -216
  174. package/dist/livePages.js.map +0 -1
  175. package/dist/liveRoom.d.ts +0 -21
  176. package/dist/liveRoom.d.ts.map +0 -1
  177. package/dist/liveRoom.js +0 -28
  178. package/dist/liveRoom.js.map +0 -1
  179. package/dist/liveShow.d.ts +0 -65
  180. package/dist/liveShow.d.ts.map +0 -1
  181. package/dist/liveShow.js +0 -65
  182. package/dist/liveShow.js.map +0 -1
  183. package/dist/missedPolls.d.ts +0 -27
  184. package/dist/missedPolls.d.ts.map +0 -1
  185. package/dist/missedPolls.js +0 -16
  186. package/dist/missedPolls.js.map +0 -1
  187. package/dist/pageOptions.d.ts +0 -149
  188. package/dist/pageOptions.d.ts.map +0 -1
  189. package/dist/pageOptions.js +0 -123
  190. package/dist/pageOptions.js.map +0 -1
  191. package/dist/pageTypes.d.ts +0 -185
  192. package/dist/pageTypes.d.ts.map +0 -1
  193. package/dist/pageTypes.js +0 -3
  194. package/dist/pageTypes.js.map +0 -1
  195. package/dist/phoneTaps.d.ts +0 -25
  196. package/dist/phoneTaps.d.ts.map +0 -1
  197. package/dist/phoneTaps.js +0 -47
  198. package/dist/phoneTaps.js.map +0 -1
  199. package/dist/pipWindow.d.ts +0 -85
  200. package/dist/pipWindow.d.ts.map +0 -1
  201. package/dist/pipWindow.js +0 -88
  202. package/dist/pipWindow.js.map +0 -1
  203. package/dist/react/clocks.d.ts +0 -29
  204. package/dist/react/clocks.d.ts.map +0 -1
  205. package/dist/react/clocks.js +0 -124
  206. package/dist/react/clocks.js.map +0 -1
  207. package/dist/react/navigation.d.ts +0 -13
  208. package/dist/react/navigation.d.ts.map +0 -1
  209. package/dist/react/navigation.js +0 -7
  210. package/dist/react/navigation.js.map +0 -1
  211. package/dist/react/platformSession.d.ts +0 -16
  212. package/dist/react/platformSession.d.ts.map +0 -1
  213. package/dist/react/platformSession.js +0 -28
  214. package/dist/react/platformSession.js.map +0 -1
  215. package/dist/react/platformSession.web.d.ts +0 -35
  216. package/dist/react/platformSession.web.d.ts.map +0 -1
  217. package/dist/react/platformSession.web.js +0 -148
  218. package/dist/react/platformSession.web.js.map +0 -1
  219. package/dist/react/replayPlayer.d.ts +0 -83
  220. package/dist/react/replayPlayer.d.ts.map +0 -1
  221. package/dist/react/replayPlayer.js +0 -315
  222. package/dist/react/replayPlayer.js.map +0 -1
  223. package/dist/react/share.d.ts +0 -22
  224. package/dist/react/share.d.ts.map +0 -1
  225. package/dist/react/share.js +0 -45
  226. package/dist/react/share.js.map +0 -1
  227. package/dist/react/shopifyProviders.d.ts +0 -82
  228. package/dist/react/shopifyProviders.d.ts.map +0 -1
  229. package/dist/react/shopifyProviders.js +0 -113
  230. package/dist/react/shopifyProviders.js.map +0 -1
  231. package/dist/react/showPages.d.ts +0 -106
  232. package/dist/react/showPages.d.ts.map +0 -1
  233. package/dist/react/showPages.js +0 -166
  234. package/dist/react/showPages.js.map +0 -1
  235. package/dist/react/showPagesOnDevice.d.ts +0 -18
  236. package/dist/react/showPagesOnDevice.d.ts.map +0 -1
  237. package/dist/react/showPagesOnDevice.js +0 -31
  238. package/dist/react/showPagesOnDevice.js.map +0 -1
  239. package/dist/react/startSignIn.d.ts +0 -3
  240. package/dist/react/startSignIn.d.ts.map +0 -1
  241. package/dist/react/startSignIn.js +0 -19
  242. package/dist/react/startSignIn.js.map +0 -1
  243. package/dist/react/systemPictureInPicture.d.ts +0 -34
  244. package/dist/react/systemPictureInPicture.d.ts.map +0 -1
  245. package/dist/react/systemPictureInPicture.js +0 -93
  246. package/dist/react/systemPictureInPicture.js.map +0 -1
  247. package/dist/react/useAccountName.d.ts +0 -8
  248. package/dist/react/useAccountName.d.ts.map +0 -1
  249. package/dist/react/useAccountName.js +0 -49
  250. package/dist/react/useAccountName.js.map +0 -1
  251. package/dist/react/useClipsPage.d.ts +0 -47
  252. package/dist/react/useClipsPage.d.ts.map +0 -1
  253. package/dist/react/useClipsPage.js +0 -130
  254. package/dist/react/useClipsPage.js.map +0 -1
  255. package/dist/react/useCommentLinkCards.d.ts +0 -6
  256. package/dist/react/useCommentLinkCards.d.ts.map +0 -1
  257. package/dist/react/useCommentLinkCards.js +0 -67
  258. package/dist/react/useCommentLinkCards.js.map +0 -1
  259. package/dist/react/useFeaturedClip.d.ts +0 -15
  260. package/dist/react/useFeaturedClip.d.ts.map +0 -1
  261. package/dist/react/useFeaturedClip.js +0 -52
  262. package/dist/react/useFeaturedClip.js.map +0 -1
  263. package/dist/react/useGiveawayEntry.d.ts +0 -59
  264. package/dist/react/useGiveawayEntry.d.ts.map +0 -1
  265. package/dist/react/useGiveawayEntry.js +0 -170
  266. package/dist/react/useGiveawayEntry.js.map +0 -1
  267. package/dist/react/useGiveawayPrize.d.ts +0 -12
  268. package/dist/react/useGiveawayPrize.d.ts.map +0 -1
  269. package/dist/react/useGiveawayPrize.js +0 -53
  270. package/dist/react/useGiveawayPrize.js.map +0 -1
  271. package/dist/react/useGiveawayPrizes.d.ts +0 -4
  272. package/dist/react/useGiveawayPrizes.d.ts.map +0 -1
  273. package/dist/react/useGiveawayPrizes.js +0 -58
  274. package/dist/react/useGiveawayPrizes.js.map +0 -1
  275. package/dist/react/useHiddenShows.d.ts +0 -10
  276. package/dist/react/useHiddenShows.d.ts.map +0 -1
  277. package/dist/react/useHiddenShows.js +0 -30
  278. package/dist/react/useHiddenShows.js.map +0 -1
  279. package/dist/react/useKeepScreenAwake.d.ts +0 -2
  280. package/dist/react/useKeepScreenAwake.d.ts.map +0 -1
  281. package/dist/react/useKeepScreenAwake.js +0 -34
  282. package/dist/react/useKeepScreenAwake.js.map +0 -1
  283. package/dist/react/useLiveAuction.d.ts +0 -106
  284. package/dist/react/useLiveAuction.d.ts.map +0 -1
  285. package/dist/react/useLiveAuction.js +0 -255
  286. package/dist/react/useLiveAuction.js.map +0 -1
  287. package/dist/react/useLiveChat.d.ts +0 -110
  288. package/dist/react/useLiveChat.d.ts.map +0 -1
  289. package/dist/react/useLiveChat.js +0 -230
  290. package/dist/react/useLiveChat.js.map +0 -1
  291. package/dist/react/useLiveGiveawaysAndPolls.d.ts +0 -95
  292. package/dist/react/useLiveGiveawaysAndPolls.d.ts.map +0 -1
  293. package/dist/react/useLiveGiveawaysAndPolls.js +0 -225
  294. package/dist/react/useLiveGiveawaysAndPolls.js.map +0 -1
  295. package/dist/react/useLivePage.d.ts +0 -136
  296. package/dist/react/useLivePage.d.ts.map +0 -1
  297. package/dist/react/useLivePage.js +0 -319
  298. package/dist/react/useLivePage.js.map +0 -1
  299. package/dist/react/useLiveShop.d.ts +0 -97
  300. package/dist/react/useLiveShop.d.ts.map +0 -1
  301. package/dist/react/useLiveShop.js +0 -197
  302. package/dist/react/useLiveShop.js.map +0 -1
  303. package/dist/react/useLiveShow.d.ts +0 -3
  304. package/dist/react/useLiveShow.d.ts.map +0 -1
  305. package/dist/react/useLiveShow.js +0 -21
  306. package/dist/react/useLiveShow.js.map +0 -1
  307. package/dist/react/useMySilentAuctionBids.d.ts +0 -29
  308. package/dist/react/useMySilentAuctionBids.d.ts.map +0 -1
  309. package/dist/react/useMySilentAuctionBids.js +0 -157
  310. package/dist/react/useMySilentAuctionBids.js.map +0 -1
  311. package/dist/react/useReplayPage.d.ts +0 -155
  312. package/dist/react/useReplayPage.d.ts.map +0 -1
  313. package/dist/react/useReplayPage.js +0 -580
  314. package/dist/react/useReplayPage.js.map +0 -1
  315. package/dist/react/useSilentAuctionLot.d.ts +0 -44
  316. package/dist/react/useSilentAuctionLot.d.ts.map +0 -1
  317. package/dist/react/useSilentAuctionLot.js +0 -168
  318. package/dist/react/useSilentAuctionLot.js.map +0 -1
  319. package/dist/react/useSilentAuctionLots.d.ts +0 -41
  320. package/dist/react/useSilentAuctionLots.d.ts.map +0 -1
  321. package/dist/react/useSilentAuctionLots.js +0 -64
  322. package/dist/react/useSilentAuctionLots.js.map +0 -1
  323. package/dist/react/useSilentAuctionRounds.d.ts +0 -15
  324. package/dist/react/useSilentAuctionRounds.d.ts.map +0 -1
  325. package/dist/react/useSilentAuctionRounds.js +0 -44
  326. package/dist/react/useSilentAuctionRounds.js.map +0 -1
  327. package/dist/replayPages.d.ts +0 -31
  328. package/dist/replayPages.d.ts.map +0 -1
  329. package/dist/replayPages.js +0 -34
  330. package/dist/replayPages.js.map +0 -1
  331. package/dist/shopifyCommerce.d.ts +0 -204
  332. package/dist/shopifyCommerce.d.ts.map +0 -1
  333. package/dist/shopifyCommerce.js +0 -217
  334. package/dist/shopifyCommerce.js.map +0 -1
  335. package/dist/shopifyIdentity.d.ts +0 -61
  336. package/dist/shopifyIdentity.d.ts.map +0 -1
  337. package/dist/shopifyIdentity.js +0 -61
  338. package/dist/shopifyIdentity.js.map +0 -1
  339. package/dist/shopifyIds.d.ts +0 -9
  340. package/dist/shopifyIds.d.ts.map +0 -1
  341. package/dist/shopifyIds.js +0 -18
  342. package/dist/shopifyIds.js.map +0 -1
  343. package/dist/showCredit.d.ts +0 -89
  344. package/dist/showCredit.d.ts.map +0 -1
  345. package/dist/showCredit.js +0 -120
  346. package/dist/showCredit.js.map +0 -1
  347. package/dist/showLinks.d.ts +0 -24
  348. package/dist/showLinks.d.ts.map +0 -1
  349. package/dist/showLinks.js +0 -23
  350. package/dist/showLinks.js.map +0 -1
  351. package/dist/showLots.d.ts +0 -44
  352. package/dist/showLots.d.ts.map +0 -1
  353. package/dist/showLots.js +0 -70
  354. package/dist/showLots.js.map +0 -1
  355. package/dist/showNames.d.ts +0 -77
  356. package/dist/showNames.d.ts.map +0 -1
  357. package/dist/showNames.js +0 -143
  358. package/dist/showNames.js.map +0 -1
  359. package/dist/showPages.d.ts +0 -56
  360. package/dist/showPages.d.ts.map +0 -1
  361. package/dist/showPages.js +0 -48
  362. package/dist/showPages.js.map +0 -1
  363. package/dist/silentAuctionFeed.d.ts +0 -49
  364. package/dist/silentAuctionFeed.d.ts.map +0 -1
  365. package/dist/silentAuctionFeed.js +0 -242
  366. package/dist/silentAuctionFeed.js.map +0 -1
  367. package/dist/silentAuctionRules.d.ts +0 -253
  368. package/dist/silentAuctionRules.d.ts.map +0 -1
  369. package/dist/silentAuctionRules.js +0 -489
  370. package/dist/silentAuctionRules.js.map +0 -1
  371. package/dist/silentAuctions.d.ts +0 -65
  372. package/dist/silentAuctions.d.ts.map +0 -1
  373. package/dist/silentAuctions.js +0 -272
  374. package/dist/silentAuctions.js.map +0 -1
  375. package/dist/storeData.d.ts +0 -16
  376. package/dist/storeData.d.ts.map +0 -1
  377. package/dist/storeData.js +0 -19
  378. package/dist/storeData.js.map +0 -1
  379. package/dist/ui/BubbleFrame.d.ts +0 -38
  380. package/dist/ui/BubbleFrame.d.ts.map +0 -1
  381. package/dist/ui/BubbleFrame.js +0 -181
  382. package/dist/ui/BubbleFrame.js.map +0 -1
  383. package/dist/ui/LiveBubble.d.ts +0 -43
  384. package/dist/ui/LiveBubble.d.ts.map +0 -1
  385. package/dist/ui/LiveBubble.js +0 -116
  386. package/dist/ui/LiveBubble.js.map +0 -1
  387. package/dist/ui/ReplayBubble.d.ts +0 -23
  388. package/dist/ui/ReplayBubble.d.ts.map +0 -1
  389. package/dist/ui/ReplayBubble.js +0 -71
  390. package/dist/ui/ReplayBubble.js.map +0 -1
  391. package/dist/ui.d.ts +0 -27
  392. package/dist/ui.d.ts.map +0 -1
  393. package/dist/ui.js +0 -34
  394. package/dist/ui.js.map +0 -1
  395. package/dist/unreadRoomMessages.d.ts +0 -26
  396. package/dist/unreadRoomMessages.d.ts.map +0 -1
  397. package/dist/unreadRoomMessages.js +0 -62
  398. package/dist/unreadRoomMessages.js.map +0 -1
  399. package/dist/viewerRules.d.ts +0 -38
  400. package/dist/viewerRules.d.ts.map +0 -1
  401. package/dist/viewerRules.js +0 -46
  402. package/dist/viewerRules.js.map +0 -1
  403. package/dist/winsAttribution.d.ts +0 -22
  404. package/dist/winsAttribution.d.ts.map +0 -1
  405. package/dist/winsAttribution.js +0 -49
  406. package/dist/winsAttribution.js.map +0 -1
  407. package/dist/zegoEngine.d.ts +0 -173
  408. package/dist/zegoEngine.d.ts.map +0 -1
  409. package/dist/zegoEngine.js +0 -1069
  410. package/dist/zegoEngine.js.map +0 -1
@@ -6,17 +6,9 @@ exports.LiveSessionProvider = LiveSessionProvider;
6
6
  * `LiveSessionProvider` / `useLiveSession` — the assembled session.
7
7
  *
8
8
  * This is the layer that turns the engine's event stream plus the polled record into one renderable
9
- * state. It owns the picture-in-picture mode machine, product resolution through the commerce adapter,
10
- * and every action a live screen fires.
11
- *
12
- * **It never ticks.** The session changes only when something happens — a room event, a record read,
13
- * an action's answer — and is the same object until one of its fields changes. It holds moments, not
14
- * clocks: when the round closes (`auction.closesAt`) and when the show started (`stream.startedAtMs`).
15
- * A component that shows a clock counts to one of them itself (`useAuctionCountdown`, `useShowClock`,
16
- * in `clocks.ts`), so only that component is drawn as the clock moves. Before 0.9.0 the session held
17
- * both clocks, and every reader — every screen in the app, since the session is app-wide — was drawn
18
- * five times a second during an auction round. Its own timers are timeouts to the moment they are for:
19
- * the round's fallback close, and the next card or reaction to run out.
9
+ * state. It owns the two clocks (the elapsed/prune tick and the faster auction tick), the
10
+ * picture-in-picture mode machine, product resolution through the commerce adapter, and every action
11
+ * a live screen fires.
20
12
  *
21
13
  * **Mount it above your navigator.** The Zego engine holds exactly one room, and two places usually
22
14
  * render the same stream — a home-screen card and the full-screen player. Owning the session per
@@ -31,20 +23,18 @@ const react_native_1 = require("react-native");
31
23
  const activeProductRetry_1 = require("../activeProductRetry");
32
24
  const cartAttributes_1 = require("../cartAttributes");
33
25
  const client_1 = require("../client");
34
- const auctionRules_1 = require("../auctionRules");
35
- const giveawayRoster_1 = require("../giveawayRoster");
36
- const showNames_1 = require("../showNames");
37
- const showLots_1 = require("../showLots");
38
- const heldComments_1 = require("../heldComments");
39
26
  const liveSelling_1 = require("../liveSelling");
40
- const missedPolls_1 = require("../missedPolls");
41
- const pageOptions_1 = require("../pageOptions");
42
- const unreadRoomMessages_1 = require("../unreadRoomMessages");
43
27
  const sdk_apptile_live_selling_native_1 = require("@tiledev/sdk-apptile-live-selling-native");
44
- const pipWindow_1 = require("../pipWindow");
45
28
  const session_1 = require("../session");
46
29
  const useStreamInfo_1 = require("./useStreamInfo");
47
30
  const videoTargets_1 = require("./videoTargets");
31
+ /** The elapsed timer and the transient-card pruning share one tick. */
32
+ const TICK_MS = 1000;
33
+ /**
34
+ * The auction clock runs faster than the session tick. Seconds are the unit a bidder acts on, and a
35
+ * 1s tick aliases against the deadline badly enough to show the same second twice and skip another.
36
+ */
37
+ const AUCTION_TICK_MS = 200;
48
38
  /**
49
39
  * How long past the deadline to wait before closing the round ourselves.
50
40
  *
@@ -53,8 +43,6 @@ const videoTargets_1 = require("./videoTargets");
53
43
  * already given up.
54
44
  */
55
45
  const AUCTION_GRACE_MS = 1000;
56
- /** The longest wait a JavaScript timer can hold (2^31 − 1 ms, about 24 days); a longer one fires at once. */
57
- const LONGEST_TIMER_MS = 2147483647;
58
46
  /**
59
47
  * How long the OS is given to actually put a picture-in-picture window up after the app goes away.
60
48
  *
@@ -64,17 +52,6 @@ const LONGEST_TIMER_MS = 2147483647;
64
52
  * means the host is talking to nobody from inside a backgrounded app.
65
53
  */
66
54
  const PIP_GRANT_MS = 1200;
67
- /**
68
- * The longest a show's room waits for the signed-in customer to load on app open (`customerLoading`),
69
- * so this viewer enters under their name. Past it the room is entered anyway: a slow sign-in must not
70
- * keep the show away.
71
- */
72
- const NAME_WAIT_MS = 10000;
73
- /**
74
- * The device said it has no picture-in-picture (L21). Module state, because it is a fact about the
75
- * device rather than about one session: once heard, arming stops and the error is not reported again.
76
- */
77
- let pipUnavailableOnDevice = false;
78
55
  const LiveSessionContext = (0, react_1.createContext)(null);
79
56
  /**
80
57
  * Reads the shared live session.
@@ -92,19 +69,12 @@ function useLiveSession() {
92
69
  /* Everything but the stream hold, which belongs to the provider component: it owns which stream this
93
70
  hook is watching, so it is the only thing that can pin it. */
94
71
  function useSessionValue(props) {
95
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
72
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
96
73
  const { streamingId, viewerName: viewerNameInput, onPipRestore } = props;
97
- const blockedNames = (_a = props.blockedNames) !== null && _a !== void 0 ? _a : showNames_1.DEFAULT_BLOCKED_VIEWER_NAMES;
98
- const blockedNamesRef = (0, react_1.useRef)(blockedNames);
99
- blockedNamesRef.current = blockedNames;
100
- /** A name the room may show for this viewer: made safe (`publicName`) and not one of the team's. */
101
- const allowedName = (name) => {
102
- const shown = (0, showNames_1.publicName)(name);
103
- return shown && !(0, showNames_1.isBlockedViewerName)(shown, blockedNames) ? shown : null;
104
- };
105
74
  const [state, dispatch] = (0, react_1.useReducer)(session_1.sessionReducer, session_1.initialSessionState);
106
75
  const [joining, setJoining] = (0, react_1.useState)(false);
107
76
  const [error, setError] = (0, react_1.useState)(null);
77
+ const [now, setNow] = (0, react_1.useState)(() => Date.now());
108
78
  const [muted, setMuted] = (0, react_1.useState)(false);
109
79
  const [pipMode, setPipMode] = (0, react_1.useState)('none');
110
80
  /**
@@ -120,23 +90,23 @@ function useSessionValue(props) {
120
90
  /** Read inside the PIP listeners, which subscribe once and would otherwise close over a stale value. */
121
91
  const handoverRef = (0, react_1.useRef)(false);
122
92
  /**
123
- * Where the picture was when the system window took it: the in-app bubble (`'inapp'`) or a
124
- * full-screen player (`'none'`). Coming back puts it there again (`whereTheWindowCameFrom`).
125
- */
126
- const windowCameFromRef = (0, react_1.useRef)('none');
127
- /**
128
- * The session is taking the window down itself (iOS: the app came back with it still up), so the
129
- * `onPipStop` that follows is not the shopper closing it.
93
+ * `onPipStart` claimed the system window that is up; cleared when it closes or is expanded.
94
+ *
95
+ * `pipMode` alone cannot say whose window just closed: an app that ends picture-in-picture on
96
+ * `AppState` `active` (Freckled Poppy's Live screen) resets `system` to `none` while the window is
97
+ * up — on Android 1ms after `onPipStart`, since the window opening reads as `active`. The close was
98
+ * then ignored and the show played on with sound behind the app.
130
99
  */
131
- const takingWindowDownRef = (0, react_1.useRef)(false);
100
+ const windowClaimedRef = (0, react_1.useRef)(false);
132
101
  /**
133
- * The show was stopped because the app is away: no window came (`PIP_GRANT_MS`), or the shopper
134
- * closed the window. Until the app is back in the foreground, a surface taking the picture does not
135
- * start it again (`bindVideoView`). Without this, closing a window opened from the full-screen
136
- * player handed the picture straight back to that player, still focused behind the window, and the
137
- * show played on with sound behind an app nobody was looking at.
102
+ * The shopper closed the system window, so the show was stopped. Until the app is back in the
103
+ * foreground, a surface taking the picture does not start it again (`bindVideoView`): closing the
104
+ * window hands the picture back to the full-screen player, still mounted behind it, and its forced
105
+ * bind would otherwise restart the show behind an app nobody is looking at.
138
106
  */
139
107
  const stoppedWhileAwayRef = (0, react_1.useRef)(false);
108
+ /** The surface that asked for the picture while `stoppedWhileAwayRef` held it back; bound on return. */
109
+ const heldBackTagRef = (0, react_1.useRef)(null);
140
110
  const viewerIdRef = (0, react_1.useRef)(null);
141
111
  const logger = (0, client_1.getLogger)();
142
112
  const identity = (0, client_1.getIdentity)();
@@ -149,9 +119,7 @@ function useSessionValue(props) {
149
119
  * name is consulted at all so a signed-in bidder is never asked to invent one.
150
120
  */
151
121
  const [chosenName, setChosenName] = (0, react_1.useState)(() => liveSelling_1.liveSelling.viewer.cachedName());
152
- // Every name here is published to the whole room, so none may be an email (`publicName`, 0.9.0), nor
153
- // a name the show's team goes by (`blockedNames`, 0.13.0).
154
- const accountName = allowedName(viewerNameInput);
122
+ const accountName = (viewerNameInput === null || viewerNameInput === void 0 ? void 0 : viewerNameInput.trim()) || null;
155
123
  (0, react_1.useEffect)(() => {
156
124
  if (accountName || chosenName)
157
125
  return;
@@ -164,109 +132,32 @@ function useSessionValue(props) {
164
132
  alive = false;
165
133
  };
166
134
  }, [accountName, chosenName]);
167
- const customerName = allowedName((_b = identity === null || identity === void 0 ? void 0 : identity.customerName) === null || _b === void 0 ? void 0 : _b.call(identity));
168
- const namedBy = (_c = accountName !== null && accountName !== void 0 ? accountName : allowedName(chosenName)) !== null && _c !== void 0 ? _c : customerName;
135
+ const customerName = (_b = (_a = identity === null || identity === void 0 ? void 0 : identity.customerName) === null || _a === void 0 ? void 0 : _a.call(identity)) !== null && _b !== void 0 ? _b : null;
136
+ const namedBy = (_c = accountName !== null && accountName !== void 0 ? accountName : chosenName) !== null && _c !== void 0 ? _c : ((customerName === null || customerName === void 0 ? void 0 : customerName.trim()) || null);
169
137
  const viewerName = namedBy !== null && namedBy !== void 0 ? namedBy : 'Anonymous';
170
- const bidderId = (_e = (_d = identity === null || identity === void 0 ? void 0 : identity.bidderId) === null || _d === void 0 ? void 0 : _d.call(identity)) !== null && _e !== void 0 ? _e : null;
171
- /**
172
- * The signed-in customer is still loading (app open, or just signed in), so their name isn't known
173
- * yet. The room waits for it, up to `NAME_WAIT_MS`: it is entered once, and the name it is entered
174
- * under is the one the host sees join. Before 0.9.2 an app opened during a show joined at once,
175
- * before the sign-in was read, and every shopper joined as "Anonymous" (2026-10-08).
176
- */
177
- const customerLoading = (_g = (_f = identity === null || identity === void 0 ? void 0 : identity.customerLoading) === null || _f === void 0 ? void 0 : _f.call(identity)) !== null && _g !== void 0 ? _g : false;
178
- /**
179
- * A comment sent now is held until the account has named the shopper (L6), and only while it loads:
180
- * an account read with no name on it isn't waited for (`waitsForAccountName`, 0.13.0).
181
- */
182
- const nameResolving = (0, heldComments_1.waitsForAccountName)(customerLoading, accountName !== null && accountName !== void 0 ? accountName : customerName);
183
- const [nameWaitOver, setNameWaitOver] = (0, react_1.useState)(false);
184
- (0, react_1.useEffect)(() => {
185
- if (!customerLoading)
186
- return;
187
- const timer = setTimeout(() => setNameWaitOver(true), NAME_WAIT_MS);
188
- return () => clearTimeout(timer);
189
- }, [customerLoading]);
190
- const waitingForName = customerLoading && !nameWaitOver;
191
- const accountNameRef = (0, react_1.useRef)(accountName);
192
- accountNameRef.current = accountName;
193
- const namedByRef = (0, react_1.useRef)(namedBy);
194
- namedByRef.current = namedBy;
195
- const nameResolvingRef = (0, react_1.useRef)(nameResolving);
196
- nameResolvingRef.current = nameResolving;
197
138
  /**
198
139
  * Pushed to the engine rather than passed at join: the room is entered once, and a name given
199
140
  * mid-show must not cost a rejoin — that interrupts the video for everyone watching on this device.
200
141
  * Comments and reactions carry the author in their own payload.
201
- *
202
- * This effect alone is too late for the FIRST comment after a name is chosen, which is why
203
- * `chooseViewerName` also sets it directly — see there.
204
142
  */
205
143
  (0, react_1.useEffect)(() => {
206
144
  liveSelling_1.liveSelling.engine.setViewerName(namedBy);
207
145
  }, [namedBy]);
146
+ /**
147
+ * The auction clock, separate from `now` so a 200ms tick does not redraw the comment pane five
148
+ * times a second on an ordinary live stream. This one only runs while a round is open.
149
+ */
150
+ const [auctionNow, setAuctionNow] = (0, react_1.useState)(() => Date.now());
208
151
  // Poll so a stream ending (or the host swapping the product set) is noticed without a manual
209
152
  // refresh. The engine's channels cover in-stream changes; this covers the record itself. With no
210
153
  // `streamingId` it follows whichever stream is on air.
211
- const { stream, refresh: refreshStreamInfo, hasRead, forcedReadAt } = (0, useStreamInfo_1.useStreamInfo)(streamingId);
154
+ const { stream, refresh: refreshStreamInfo } = (0, useStreamInfo_1.useStreamInfo)(streamingId);
212
155
  const watching = streamingId !== null && streamingId !== void 0 ? streamingId : stream === null || stream === void 0 ? void 0 : stream.streamingId;
213
- /** The comment pipeline; `heldComments` uses it, so it is defined before the show reset below. */
214
- const deliverComment = (0, react_1.useCallback)(async (text, options) => {
215
- var _a;
216
- try {
217
- // The host mutes by device; a per-install viewer id is the same granularity.
218
- const deviceId = (_a = viewerIdRef.current) !== null && _a !== void 0 ? _a : (await liveSelling_1.liveSelling.viewer.id());
219
- const own = await liveSelling_1.liveSelling.engine.sendComment(text, deviceId, options);
220
- if (own)
221
- dispatch({ kind: 'ownComment', comment: own });
222
- }
223
- catch (caught) {
224
- (0, client_1.getLogger)().error(caught, { at: 'liveSession.sendComment' });
225
- }
226
- }, []);
227
- const heldCommentsRef = (0, react_1.useRef)(null);
228
- if (!heldCommentsRef.current) {
229
- heldCommentsRef.current = new heldComments_1.HeldComments(({ text, options }) => deliverComment(text, options));
230
- }
231
156
  (0, react_1.useEffect)(() => {
232
- var _a;
233
157
  dispatch({ kind: 'reset' });
234
158
  setError(null);
235
- // A comment held for the last show's room must not be said in this one.
236
- (_a = heldCommentsRef.current) === null || _a === void 0 ? void 0 : _a.drop();
237
- }, [watching]);
238
- /**
239
- * The account has loaded: say the name to the engine first, then send what was waiting for it, in
240
- * order. Loaded with no name, they go under the session's name (one typed on this phone, or
241
- * "Anonymous"), as they would after the longest wait: an app asks for a name before sending.
242
- */
243
- (0, react_1.useEffect)(() => {
244
- var _a;
245
- if (nameResolving || !((_a = heldCommentsRef.current) === null || _a === void 0 ? void 0 : _a.size))
246
- return;
247
- liveSelling_1.liveSelling.engine.setViewerName(namedBy);
248
- void heldCommentsRef.current.release();
249
- }, [namedBy, nameResolving]);
250
- /**
251
- * Room messages this version doesn't read (ENG-969, `unreadRoomMessages.ts`): the first of each kind
252
- * per show goes to the app's `onWarning` (`reportLiveWarning`; the console without one), so a message
253
- * the dashboard renamed or moved is seen. Not the config's `logger`, which is silent unless an app sets one.
254
- */
255
- const unreadRoomMessagesRef = (0, react_1.useRef)(new unreadRoomMessages_1.UnreadRoomMessages());
256
- (0, react_1.useEffect)(() => {
257
- unreadRoomMessagesRef.current = new unreadRoomMessages_1.UnreadRoomMessages();
258
159
  }, [watching]);
259
160
  (0, react_1.useEffect)(() => liveSelling_1.liveSelling.engine.subscribe((event) => {
260
- if (event.type === 'unknown') {
261
- const kind = unreadRoomMessagesRef.current.firstOfItsKind(event.channel, event.payload);
262
- if (kind) {
263
- (0, pageOptions_1.reportLiveWarning)(new Error(`Live room: a message this version doesn't read (${kind})`), {
264
- at: 'liveSession.unreadRoomMessage',
265
- channel: event.channel,
266
- message: (0, unreadRoomMessages_1.reportedCopyOf)(event.payload),
267
- });
268
- }
269
- }
270
161
  dispatch({ kind: 'event', event, at: Date.now() });
271
162
  }), []);
272
163
  (0, react_1.useEffect)(() => {
@@ -277,9 +168,6 @@ function useSessionValue(props) {
277
168
  // effect re-runs and the viewer session takes the room back.
278
169
  if (state.guestMode)
279
170
  return;
280
- // Entered once the shopper's name is known (`waitingForName`); this effect runs again when it is.
281
- if (waitingForName)
282
- return;
283
171
  /**
284
172
  * Off-device the engine is the no-op build, so a join would *succeed* — every stubbed call
285
173
  * resolves — and then no room state would ever arrive, leaving the status on `connecting` for
@@ -329,10 +217,9 @@ function useSessionValue(props) {
329
217
  .catch((caught) => logger.error(caught, { at: 'liveSession.leave' }));
330
218
  };
331
219
  // viewerName is intentionally excluded: it changes when the customer loads, and rejoining the
332
- // room mid-stream to relabel comments is not worth a video interruption. `waitingForName` only
333
- // ever goes from true to false, before the room is entered.
220
+ // room mid-stream to relabel comments is not worth a video interruption.
334
221
  // eslint-disable-next-line react-hooks/exhaustive-deps
335
- }, [stream === null || stream === void 0 ? void 0 : stream.streamingId, stream === null || stream === void 0 ? void 0 : stream.status, state.guestMode, waitingForName]);
222
+ }, [stream === null || stream === void 0 ? void 0 : stream.streamingId, stream === null || stream === void 0 ? void 0 : stream.status, state.guestMode]);
336
223
  /**
337
224
  * Keep the muted list in step with the polled record.
338
225
  *
@@ -340,71 +227,14 @@ function useSessionValue(props) {
340
227
  * importantly an *unmute*, which is otherwise invisible until the app restarts. Keyed on the joined
341
228
  * ids because the array is a fresh object on every poll.
342
229
  */
343
- const mutedKey = ((_h = stream === null || stream === void 0 ? void 0 : stream.mutedDeviceIds) !== null && _h !== void 0 ? _h : []).join(',');
230
+ const mutedKey = ((_d = stream === null || stream === void 0 ? void 0 : stream.mutedDeviceIds) !== null && _d !== void 0 ? _d : []).join(',');
344
231
  (0, react_1.useEffect)(() => {
345
232
  if (!stream)
346
233
  return;
347
234
  liveSelling_1.liveSelling.engine.setMutedDeviceIds(mutedKey ? mutedKey.split(',') : []);
348
235
  // eslint-disable-next-line react-hooks/exhaustive-deps
349
236
  }, [mutedKey]);
350
- /** The room's and the record's view, before the off-air wait below has its say. */
351
- const derivedStatus = (0, session_1.deriveStatus)(state, !!stream, joining, error, (stream === null || stream === void 0 ? void 0 : stream.status) === 'live');
352
- /**
353
- * Nothing on air, settled — Freckled Poppy's `NOTHING_ON_AIR_MS`, moved here.
354
- *
355
- * With no record at all `deriveStatus` says `loading`, and keeps saying it: a deep link to a show
356
- * that has gone, or a session with nothing live, spun for ever. After `offAirGraceMs` (4 s) with a
357
- * read finished, nothing live in it, and the room not reconnecting, the status becomes `ended`.
358
- *
359
- * Every forced read (`refreshStreamRecords()`, which a screen calls on focus) starts the wait again.
360
- * That is the guard against a stale record: a push tap lands on a screen whose last read predates
361
- * the show, and without the restart the show would be declared over before the fresh read came
362
- * back.
363
- */
364
- const nothingOnAir = (0, session_1.isNothingOnAir)({
365
- hasRead,
366
- streamStatus: (_j = stream === null || stream === void 0 ? void 0 : stream.status) !== null && _j !== void 0 ? _j : null,
367
- status: derivedStatus,
368
- });
369
- const graceMs = (0, client_1.offAirGraceMs)();
370
- const [settledOffAir, setSettledOffAir] = (0, react_1.useState)(false);
371
- (0, react_1.useEffect)(() => {
372
- setSettledOffAir(false);
373
- if (!nothingOnAir)
374
- return;
375
- const timer = setTimeout(() => setSettledOffAir(true), graceMs);
376
- return () => clearTimeout(timer);
377
- }, [nothingOnAir, forcedReadAt, graceMs]);
378
- const status = (0, session_1.withOffAirSettled)(derivedStatus, settledOffAir);
379
- /**
380
- * A poll the room never told this phone about (ENG-969, `missedPolls.ts`): while a show is on air
381
- * with no poll up, its record is read for one every `MISSED_POLL_READ_MS`, so a poll opened
382
- * meanwhile shows within that time rather than after the shopper leaves and comes back.
383
- *
384
- * Only the poll is taken from the read, through `pollSynced`, which keeps the state as it is unless
385
- * the poll is one this phone has never seen. It doesn't go through `useStreamInfo`: a record set every
386
- * 20 s would re-render everything that reads the session and restart the off-air wait, and that file
387
- * keeps no timer by design (read its header). This one is the exception, for as long as the room's
388
- * own `START_POLL` can't be relied on: one record by id, per watching phone, every 20 s, only while
389
- * no poll is up.
390
- */
391
- const readingForMissedPoll = (0, missedPolls_1.readsForMissedPoll)({ status, connected: state.connected, pollShowing: !!state.poll });
392
- (0, react_1.useEffect)(() => {
393
- if (!readingForMissedPoll || !watching)
394
- return;
395
- const timer = setInterval(() => {
396
- liveSelling_1.liveSelling.streams
397
- .byId(watching)
398
- .then((record) => {
399
- var _a;
400
- if (record === null || record === void 0 ? void 0 : record.poll)
401
- dispatch({ kind: 'pollSynced', poll: record.poll, results: (_a = record.pollResults) !== null && _a !== void 0 ? _a : null });
402
- })
403
- .catch((caught) => logger.error(caught, { at: 'liveSession.missedPollRead', streamingId: watching }));
404
- }, missedPolls_1.MISSED_POLL_READ_MS);
405
- return () => clearInterval(timer);
406
- // eslint-disable-next-line react-hooks/exhaustive-deps
407
- }, [readingForMissedPoll, watching]);
237
+ const status = (0, session_1.deriveStatus)(state, !!stream, joining, error, (stream === null || stream === void 0 ? void 0 : stream.status) === 'live');
408
238
  // A PIP surface outlives the screen that opened it, so nothing else would take it down when the
409
239
  // host ends the stream — it would sit there over the app showing a frozen last frame.
410
240
  (0, react_1.useEffect)(() => {
@@ -416,19 +246,15 @@ function useSessionValue(props) {
416
246
  // The host's end broadcast reaches us long before the polled record catches up. Stop the picture,
417
247
  // then force a refetch so every poll-driven surface drops the stream instead of waiting out the
418
248
  // interval.
419
- //
420
- // Keyed on the status BEFORE the off-air wait: an end the wait declared has no record to catch up
421
- // with, and its forced read would restart the wait — which would end the show again four seconds
422
- // later, for ever.
423
249
  (0, react_1.useEffect)(() => {
424
- if (derivedStatus !== 'ended')
250
+ if (status !== 'ended')
425
251
  return;
426
252
  liveSelling_1.liveSelling.engine
427
253
  .stopPlayback()
428
254
  .catch((caught) => logger.error(caught, { at: 'liveSession.stopOnEnd' }));
429
255
  (0, useStreamInfo_1.refreshStreamRecords)();
430
256
  // eslint-disable-next-line react-hooks/exhaustive-deps
431
- }, [derivedStatus]);
257
+ }, [status]);
432
258
  /**
433
259
  * Whether a mounted surface has asked to hand over to a system window.
434
260
  *
@@ -446,29 +272,16 @@ function useSessionValue(props) {
446
272
  // `pipMode !== 'none'` covers the in-app bubble; `handoverWanted` is what lets the FULL-SCREEN
447
273
  // player hand over too. Without it, minimising from the player armed nothing, no window opened,
448
274
  // and the audio played on behind the app because the plugin declares the `audio` background mode.
449
- //
450
- // What was last armed, and when it was last disarmed, are what decide on Android whether a window
451
- // that opens is ours — see `ownsSystemPipWindow`.
452
- //
453
- // Only while the show is `playing` (`shouldArmSystemWindow`): joining, a host off camera and an ended
454
- // show have no picture to put in a window. A window already up stays armed whatever the status does.
455
- const armedRef = (0, react_1.useRef)(false);
456
- const disarmedAtRef = (0, react_1.useRef)(0);
457
275
  (0, react_1.useEffect)(() => {
458
276
  if (!sdk_apptile_live_selling_native_1.isLivePipSupported)
459
277
  return;
460
- const armed = (0, pipWindow_1.shouldArmSystemWindow)({ pipMode, handoverWanted, status });
461
- if (armedRef.current && !armed)
462
- disarmedAtRef.current = Date.now();
463
- armedRef.current = armed;
464
- // A device without picture-in-picture answers every arming with an error (L21); stop asking.
465
- if (!(armed && pipUnavailableOnDevice))
466
- void sdk_apptile_live_selling_native_1.livePip.setArmed(armed);
278
+ const armed = pipMode !== 'none' || handoverWanted;
279
+ void sdk_apptile_live_selling_native_1.livePip.setArmed(armed);
467
280
  liveSelling_1.liveSelling.engine
468
281
  .setBackgroundVideoEnabled(armed)
469
282
  .catch((caught) => logger.error(caught, { at: 'liveSession.backgroundVideo' }));
470
283
  // eslint-disable-next-line react-hooks/exhaustive-deps
471
- }, [pipMode, handoverWanted, status]);
284
+ }, [pipMode, handoverWanted]);
472
285
  /**
473
286
  * The sound must not outlive the app when no window follows.
474
287
  *
@@ -477,16 +290,11 @@ function useSessionValue(props) {
477
290
  * declared. So a backgrounded session gives the OS `PIP_GRANT_MS` to produce a window and stops
478
291
  * playback if none arrived. `pipModeRef` rather than `pipMode`, because this subscribes once and
479
292
  * the answer is only knowable when the timer fires.
480
- *
481
- * A show stopped here stays stopped until the app is back (`stoppedWhileAwayRef`): a surface that
482
- * re-claims meanwhile — its status changed, a window was closed — would otherwise start it again
483
- * behind the app. Back in the foreground, `LiveVideoTarget` takes the picture again by itself.
484
293
  */
485
294
  (0, react_1.useEffect)(() => {
486
295
  let grant = null;
487
296
  const subscription = react_native_1.AppState.addEventListener('change', (next) => {
488
297
  if (next === 'active') {
489
- stoppedWhileAwayRef.current = false;
490
298
  if (grant)
491
299
  clearTimeout(grant);
492
300
  grant = null;
@@ -500,7 +308,6 @@ function useSessionValue(props) {
500
308
  grant = null;
501
309
  if (pipModeRef.current === 'system')
502
310
  return;
503
- stoppedWhileAwayRef.current = true;
504
311
  liveSelling_1.liveSelling.engine
505
312
  .stopPlayback()
506
313
  .catch((caught) => logger.error(caught, { at: 'liveSession.noPipWindow' }));
@@ -518,50 +325,25 @@ function useSessionValue(props) {
518
325
  return;
519
326
  /**
520
327
  * Only ours if this session had a surface up first — either the in-app bubble, or the full-screen
521
- * player having asked for the handover — or, on Android, if this session armed the window the OS
522
- * just opened. Anything else minimising into a system window raises the same event, and taking it
523
- * means the live session believes it is in a PIP window it never opened. See `ownsSystemPipWindow`
524
- * for why Android cannot go by the handover alone.
328
+ * player having asked for the handover. Anything else minimising into a system window raises the
329
+ * same event, and taking it means the live session believes it is in a PIP window it never
330
+ * opened.
525
331
  */
526
332
  const offStart = sdk_apptile_live_selling_native_1.livePip.addListener('onPipStart', () => {
527
- const ours = (0, pipWindow_1.ownsSystemPipWindow)({
528
- platform: react_native_1.Platform.OS,
529
- pipMode: pipModeRef.current,
530
- handoverWanted: handoverRef.current,
531
- armed: armedRef.current,
532
- disarmedAt: disarmedAtRef.current,
533
- now: Date.now(),
534
- });
535
- if (!ours)
333
+ if (pipModeRef.current !== 'inapp' && !handoverRef.current)
536
334
  return;
537
- windowCameFromRef.current = (0, pipWindow_1.whereTheWindowCameFrom)(pipModeRef.current, windowCameFromRef.current);
538
- takingWindowDownRef.current = false;
335
+ windowClaimedRef.current = true;
539
336
  setPipMode('system');
540
337
  });
541
- /**
542
- * Coming back: the picture goes back to where the window took it from. The in-app bubble is the
543
- * app's own surface and is still mounted, so `'inapp'` is all it takes; a full-screen player is a
544
- * route only the app can navigate to, so it hears `onPipRestore`. Set in the same event as the
545
- * window's end, so no render ever sees `'none'` on the way back to the bubble: a card that claims
546
- * on `'none'` would take the picture for one frame and leave a black one behind.
547
- */
548
- const giveThePictureBack = () => {
549
- const place = windowCameFromRef.current;
550
- setPipMode(place);
551
- if (place === 'none')
552
- onPipRestore === null || onPipRestore === void 0 ? void 0 : onPipRestore(watching);
553
- };
554
338
  // Expanding and closing both end in `onPipStop`; `restored` is the only thing that tells them
555
- // apart, and the expand path is handled by `onPipRestore` instead. Closing stops the show, and it
556
- // stays stopped until the app is back in the foreground (`stoppedWhileAwayRef`).
339
+ // apart, and the expand path is handled by `onPipRestore` instead. A window this session claimed
340
+ // stops the show on close whatever `pipMode` says now (`windowClaimedRef`).
557
341
  const offStop = sdk_apptile_live_selling_native_1.livePip.addListener('onPipStop', ({ restored }) => {
558
- if (takingWindowDownRef.current) {
559
- takingWindowDownRef.current = false;
560
- return;
561
- }
342
+ const claimedAtStart = windowClaimedRef.current;
343
+ windowClaimedRef.current = false;
562
344
  if (restored)
563
345
  return;
564
- if (pipModeRef.current !== 'system')
346
+ if (pipModeRef.current !== 'system' && !claimedAtStart)
565
347
  return;
566
348
  stoppedWhileAwayRef.current = true;
567
349
  setPipMode('none');
@@ -570,37 +352,17 @@ function useSessionValue(props) {
570
352
  .catch((caught) => logger.error(caught, { at: 'liveSession.pipDismissed' }));
571
353
  });
572
354
  const offRestore = sdk_apptile_live_selling_native_1.livePip.addListener('onPipRestore', () => {
355
+ windowClaimedRef.current = false;
573
356
  if (pipModeRef.current !== 'system')
574
357
  return;
575
- giveThePictureBack();
576
- });
577
- /* iOS: back in the app with the window still up (see `isWindowStillUpOnReturn`). The picture goes
578
- back where it was, then the window is taken down; its `onPipStop` is ours, not a close. */
579
- const offReturn = react_native_1.AppState.addEventListener('change', (next) => {
580
- if (next !== 'active')
581
- return;
582
- if (!(0, pipWindow_1.isWindowStillUpOnReturn)(react_native_1.Platform.OS, pipModeRef.current))
583
- return;
584
- takingWindowDownRef.current = true;
585
- giveThePictureBack();
586
- void sdk_apptile_live_selling_native_1.livePip.stop();
587
- });
588
- /* "Not available on this device" is a fact about the device, reported once as a warning — not an
589
- error filed every time the bubble opens (L21). */
590
- const offError = sdk_apptile_live_selling_native_1.livePip.addListener('onPipError', ({ message }) => {
591
- if ((0, pipWindow_1.isPipUnavailableMessage)(message)) {
592
- if (!pipUnavailableOnDevice)
593
- (0, client_1.logWarning)(new Error(message), { at: 'liveSession.pipUnavailable' });
594
- pipUnavailableOnDevice = true;
595
- return;
596
- }
597
- logger.error(new Error(message), { at: 'liveSession.pipError' });
358
+ setPipMode('none');
359
+ onPipRestore === null || onPipRestore === void 0 ? void 0 : onPipRestore(watching);
598
360
  });
361
+ const offError = sdk_apptile_live_selling_native_1.livePip.addListener('onPipError', ({ message }) => logger.error(new Error(message), { at: 'liveSession.pipError' }));
599
362
  return () => {
600
363
  offStart === null || offStart === void 0 ? void 0 : offStart();
601
364
  offStop === null || offStop === void 0 ? void 0 : offStop();
602
365
  offRestore === null || offRestore === void 0 ? void 0 : offRestore();
603
- offReturn.remove();
604
366
  offError === null || offError === void 0 ? void 0 : offError();
605
367
  };
606
368
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -611,6 +373,19 @@ function useSessionValue(props) {
611
373
  const subscription = react_native_1.AppState.addEventListener('change', (next) => {
612
374
  if (next !== 'active')
613
375
  return;
376
+ if (stoppedWhileAwayRef.current) {
377
+ // The shopper closed the window and came back: `stopPlayback` dropped the bound view, so
378
+ // there is nothing to refresh — bind the surface that asked for the picture while away.
379
+ stoppedWhileAwayRef.current = false;
380
+ const tag = heldBackTagRef.current;
381
+ heldBackTagRef.current = null;
382
+ if (tag == null)
383
+ return;
384
+ liveSelling_1.liveSelling.engine
385
+ .bindView(tag, true)
386
+ .catch((caught) => logger.error(caught, { at: 'liveSession.bindViewOnReturn' }));
387
+ return;
388
+ }
614
389
  liveSelling_1.liveSelling.engine
615
390
  .refreshPlayback()
616
391
  .catch((caught) => logger.error(caught, { at: 'liveSession.refreshPlayback' }));
@@ -618,45 +393,39 @@ function useSessionValue(props) {
618
393
  return () => subscription.remove();
619
394
  // eslint-disable-next-line react-hooks/exhaustive-deps
620
395
  }, []);
621
- /**
622
- * Sold cards, cart cards and reactions leave when their time is up (`SOLD_CARD_MS`, `CART_CARD_MS`,
623
- * `REACTION_MS`): one timer, to the moment the next one runs out (`nextExpiryAt`), set again whenever
624
- * that moment changes. Nothing runs with none on screen.
625
- *
626
- * The prune is told it is that moment even if the timer fires a millisecond early, so the card it
627
- * was set for is always the one that goes — otherwise nothing would change, the moment would stay
628
- * the same, and no timer would be set again.
629
- */
630
- const nextExpiry = (0, session_1.nextExpiryAt)(state);
631
396
  (0, react_1.useEffect)(() => {
632
- if (nextExpiry === null)
397
+ if (status !== 'playing' &&
398
+ state.sold.length === 0 &&
399
+ state.cartAnnouncements.length === 0 &&
400
+ state.reactions.length === 0) {
633
401
  return;
634
- const timer = setTimeout(() => {
635
- dispatch({ kind: 'prune', now: Math.max(Date.now(), nextExpiry) });
636
- }, Math.max(0, nextExpiry - Date.now()));
637
- return () => clearTimeout(timer);
638
- }, [nextExpiry]);
402
+ }
403
+ const timer = setInterval(() => {
404
+ const at = Date.now();
405
+ setNow(at);
406
+ dispatch({ kind: 'prune', now: at });
407
+ }, TICK_MS);
408
+ return () => clearInterval(timer);
409
+ }, [status, state.sold.length, state.cartAnnouncements.length, state.reactions.length]);
639
410
  /**
640
- * The round's fallback close. The host normally closes the round; when nothing arrives by the
641
- * deadline plus the grace period, the round is over as far as this device is concerned. One timer to
642
- * that moment, set again when a late bid moves the deadline, and gone when the round closes.
643
- *
644
- * Destructured rather than read off `state`, so the timer is keyed on exactly the three things that
645
- * move the moment. An open round with no deadline yet (a bid heard before the opening, carrying
646
- * none) closes at once, as it did on the old 200 ms clock: there is nothing to wait for.
411
+ * The auction clock. Only runs while a round is open, so it costs nothing on a normal live stream.
412
+ * It also owns the fallback close: past the deadline plus the grace period with no word from the
413
+ * host, the round is over as far as this device is concerned.
647
414
  */
648
415
  const { biddingOpen, endsAtMs, serverOffsetMs } = state;
649
416
  (0, react_1.useEffect)(() => {
650
417
  if (!biddingOpen)
651
418
  return;
652
- const closeAt = endsAtMs - serverOffsetMs + AUCTION_GRACE_MS;
653
- const wait = Math.max(0, closeAt - Date.now());
654
- // A timer holds at most 2^31 − 1 ms (about 24 days) and fires at once past that. A deadline that
655
- // far away is bad data, and the old clock never closed it early either.
656
- if (wait > LONGEST_TIMER_MS)
657
- return;
658
- const timer = setTimeout(() => dispatch({ kind: 'auctionExpired' }), wait);
659
- return () => clearTimeout(timer);
419
+ const timer = setInterval(() => {
420
+ const at = Date.now();
421
+ setAuctionNow(at);
422
+ // Destructured rather than read off `state`, so the closure cannot go stale against a deadline
423
+ // a late bid has already moved — the deps re-arm it when one does.
424
+ if (endsAtMs - (at + serverOffsetMs) < -AUCTION_GRACE_MS) {
425
+ dispatch({ kind: 'auctionExpired' });
426
+ }
427
+ }, AUCTION_TICK_MS);
428
+ return () => clearInterval(timer);
660
429
  }, [biddingOpen, endsAtMs, serverOffsetMs]);
661
430
  /**
662
431
  * Giveaway state off the polled record.
@@ -666,7 +435,8 @@ function useSessionValue(props) {
666
435
  * enter a giveaway they are already in.
667
436
  */
668
437
  const activeGiveaway = (0, react_1.useMemo)(() => { var _a; return (_a = stream === null || stream === void 0 ? void 0 : stream.giveaways.find((giveaway) => giveaway.status === 'active')) !== null && _a !== void 0 ? _a : null; }, [stream]);
669
- const customerRef = (_l = (_k = identity === null || identity === void 0 ? void 0 : identity.customerRef) === null || _k === void 0 ? void 0 : _k.call(identity)) !== null && _l !== void 0 ? _l : null;
438
+ const bidderId = (_f = (_e = identity === null || identity === void 0 ? void 0 : identity.bidderId) === null || _e === void 0 ? void 0 : _e.call(identity)) !== null && _f !== void 0 ? _f : null;
439
+ const customerRef = (_h = (_g = identity === null || identity === void 0 ? void 0 : identity.customerRef) === null || _g === void 0 ? void 0 : _g.call(identity)) !== null && _h !== void 0 ? _h : null;
670
440
  /**
671
441
  * Closes the gap between the realtime giveaway start and the polled record it depends on.
672
442
  *
@@ -682,7 +452,6 @@ function useSessionValue(props) {
682
452
  void refreshStreamInfo();
683
453
  }, [giveawayKnown, refreshStreamInfo]);
684
454
  (0, react_1.useEffect)(() => {
685
- var _a;
686
455
  if (!activeGiveaway)
687
456
  return;
688
457
  const entries = activeGiveaway.entries.filter((entry) => entry.active);
@@ -692,37 +461,8 @@ function useSessionValue(props) {
692
461
  entryCount: entries.length,
693
462
  registered: !!bidderId && entries.some((entry) => entry.userId === bidderId),
694
463
  bidderId,
695
- entrantNames: activeGiveaway.entrantNames,
696
- startedAtMs: (_a = activeGiveaway.startedAtMs) !== null && _a !== void 0 ? _a : null,
697
464
  });
698
465
  }, [activeGiveaway, bidderId]);
699
- /**
700
- * The draw's roster — ENG-705, moved here from Freckled Poppy's Live screen.
701
- *
702
- * `giveaway_end` names the winner and nobody else, and reaches the room before the gateway has
703
- * written the entrants onto the record. When the roster latched while the lot was open is empty
704
- * too, the record is asked again every 700 ms for up to 5 s; the first read with names is taken and
705
- * kept (`giveawayRoster`), and running out of time lets the reveal go ahead without one.
706
- */
707
- const rosterWait = state.giveawayResult && !state.giveawayResult.entrantNamesReady
708
- ? `${state.giveawayResult.storeProductId}\u0000${state.giveawayResult.winnerName}`
709
- : null;
710
- (0, react_1.useEffect)(() => {
711
- if (!rosterWait)
712
- return;
713
- return (0, giveawayRoster_1.waitForGiveawayRoster)({
714
- readRecord: () => void refreshStreamInfo(),
715
- onGiveUp: () => dispatch({ kind: 'giveawayRosterTimedOut' }),
716
- });
717
- }, [rosterWait, refreshStreamInfo]);
718
- (0, react_1.useEffect)(() => {
719
- const result = state.giveawayResult;
720
- if (!result || result.entrantNamesReady || !stream)
721
- return;
722
- const names = (0, giveawayRoster_1.rosterFromRecord)(stream.giveaways, result.storeProductId);
723
- if (names.length)
724
- dispatch({ kind: 'giveawayRoster', storeProductId: result.storeProductId, names });
725
- }, [state.giveawayResult, stream]);
726
466
  /**
727
467
  * The poll off the RECORD, for one this device never heard open — DEL-2769.
728
468
  *
@@ -781,93 +521,29 @@ function useSessionValue(props) {
781
521
  }));
782
522
  }, [stream, state.removedStoreProductIds]);
783
523
  /**
784
- * The host featured a lot (`PRODUCT_CHANGE`): read the record again, once per change.
785
- *
786
- * Two things live only on the record and change at exactly this moment:
524
+ * A lot the host featured that this record has never heard of.
787
525
  *
788
- * - **The lot number.** On a company with show-gated products the gateway issues `sell_id` when the
789
- * host SHOWS the lot (DEL-2885), and nothing re-reads the record mid-watch — so `sellId` stayed
790
- * null for the whole session. Freckled Poppy forced this read from its Live screen; it lives here
791
- * now, for every app.
792
- * - **A link lot added mid-stream.** Its name, thumbnail and URL exist nowhere else, so without the
793
- * read it resolved to nothing and `activeProduct` fell back to a different product.
526
+ * `productChange` adds the id to the extras, so a CATALOGUE lot survives: the id goes to
527
+ * `productsByIds` and the storefront answers for it immediately. A LINK lot cannot — everything
528
+ * it has to show (name, thumbnail, URL) lives only on the stream record, which is polled on a
529
+ * five-minute timer. So a link lot added and featured mid-stream resolved to nothing, and
530
+ * `activeProduct` fell back to `products[0]` — showing the room a different product entirely.
794
531
  *
795
- * Skipped when the record already lists the lot with its number: the read would bring nothing new.
532
+ * Re-reading the record is what makes it appear. Once per id: an id that is genuinely absent
533
+ * must not turn into a poll every render.
796
534
  */
535
+ const chasedRecordFor = (0, react_1.useRef)(null);
797
536
  (0, react_1.useEffect)(() => {
798
- var _a;
799
537
  const active = state.activeStoreProductId;
800
- if (!active)
801
- return;
802
- const row = (_a = streamRef.current) === null || _a === void 0 ? void 0 : _a.products.find((product) => product.storeProductId === active);
803
- if (row === null || row === void 0 ? void 0 : row.sellId)
804
- return;
805
- void refreshStreamInfo();
806
- }, [state.activeStoreProductId, refreshStreamInfo]);
807
- /**
808
- * What the room said before this device arrived, put in front of the comments — once per show.
809
- *
810
- * Read when the show is known to be live, and dropped if the show changed while it was in flight.
811
- * `mergeCommentHistory` (in the reducer) leaves out anything the room has already delivered and
812
- * renames the host's stored "You" to the host.
813
- */
814
- const liveStreamingId = (stream === null || stream === void 0 ? void 0 : stream.status) === 'live' ? stream.streamingId : null;
815
- (0, react_1.useEffect)(() => {
816
- if (!liveStreamingId || react_native_1.Platform.OS === 'web')
538
+ if (!active || !stream)
817
539
  return;
818
- let cancelled = false;
819
- liveSelling_1.liveSelling.streams
820
- .commentHistory(liveStreamingId)
821
- .then((history) => {
822
- var _a, _b;
823
- if (cancelled || !history.length)
824
- return;
825
- dispatch({
826
- kind: 'commentHistory',
827
- history,
828
- hostName: (_b = (_a = streamRef.current) === null || _a === void 0 ? void 0 : _a.hostName) !== null && _b !== void 0 ? _b : null,
829
- ownName: namedByRef.current,
830
- });
831
- })
832
- .catch((caught) => logger.error(caught, { at: 'liveSession.commentHistory', streamingId: liveStreamingId }));
833
- return () => {
834
- cancelled = true;
835
- };
836
- // eslint-disable-next-line react-hooks/exhaustive-deps
837
- }, [liveStreamingId]);
838
- /**
839
- * The pinned comment, off the RECORD — for arrival, and for every reconnect.
840
- *
841
- * The room's `PINNED_COMMENT_CHANGED` reaches the reducer directly and wins until the record's own
842
- * pin changes. Dispatched only when the record's pin CHANGES (keyed with the show), so a read
843
- * taken before an unpin cannot bring the old pin back — the same precedence the record's poll has.
844
- *
845
- * A broadcast sent while the room was down never arrives, so a reconnect re-reads the record and
846
- * the first record after it is taken whatever it says. Joining counts as a reconnect, so arriving
847
- * costs one extra read.
848
- */
849
- const recordPin = (_m = stream === null || stream === void 0 ? void 0 : stream.pinnedComment) !== null && _m !== void 0 ? _m : null;
850
- const recordPinKey = `${watching !== null && watching !== void 0 ? watching : ''}\u0000${(_o = recordPin === null || recordPin === void 0 ? void 0 : recordPin.id) !== null && _o !== void 0 ? _o : ''}\u0000${(_p = recordPin === null || recordPin === void 0 ? void 0 : recordPin.text) !== null && _p !== void 0 ? _p : ''}`;
851
- const lastRecordPinKey = (0, react_1.useRef)(null);
852
- const takeNextRecordPin = (0, react_1.useRef)(false);
853
- (0, react_1.useEffect)(() => {
854
- if (!stream)
540
+ if (stream.products.some((product) => product.storeProductId === active))
855
541
  return;
856
- if (recordPinKey === lastRecordPinKey.current && !takeNextRecordPin.current)
542
+ if (chasedRecordFor.current === active)
857
543
  return;
858
- lastRecordPinKey.current = recordPinKey;
859
- takeNextRecordPin.current = false;
860
- dispatch({ kind: 'pinnedCommentSynced', comment: recordPin });
861
- // eslint-disable-next-line react-hooks/exhaustive-deps
862
- }, [stream, recordPinKey]);
863
- const wasConnected = (0, react_1.useRef)(false);
864
- (0, react_1.useEffect)(() => {
865
- if (state.connected && !wasConnected.current) {
866
- takeNextRecordPin.current = true;
867
- void refreshStreamInfo();
868
- }
869
- wasConnected.current = state.connected;
870
- }, [state.connected, refreshStreamInfo]);
544
+ chasedRecordFor.current = active;
545
+ refreshStreamInfo();
546
+ }, [state.activeStoreProductId, stream, refreshStreamInfo]);
871
547
  /**
872
548
  * Resolved through the commerce adapter, keyed on the joined ids so a mid-stream product add
873
549
  * refetches and an unchanged set does not. Link lots are held out: they have no id the catalogue
@@ -909,7 +585,7 @@ function useSessionValue(props) {
909
585
  if (!activeRetryRef.current) {
910
586
  activeRetryRef.current = new activeProductRetry_1.ActiveProductRetry(() => setCatalogueRetry((n) => n + 1));
911
587
  }
912
- const featuredId = (_s = (_q = state.activeStoreProductId) !== null && _q !== void 0 ? _q : (_r = stream === null || stream === void 0 ? void 0 : stream.products.find((product) => product.isCurrent)) === null || _r === void 0 ? void 0 : _r.storeProductId) !== null && _s !== void 0 ? _s : null;
588
+ const featuredId = (_l = (_j = state.activeStoreProductId) !== null && _j !== void 0 ? _j : (_k = stream === null || stream === void 0 ? void 0 : stream.products.find((product) => product.isCurrent)) === null || _k === void 0 ? void 0 : _k.storeProductId) !== null && _l !== void 0 ? _l : null;
913
589
  const featuredCatalogueId = featuredId && productKey.split(',').includes(featuredId) ? featuredId : null;
914
590
  const answerSeq = (catalogueAnswer === null || catalogueAnswer === void 0 ? void 0 : catalogueAnswer.key) === productKey ? catalogueAnswer.seq : null;
915
591
  const hasFeatured = !!featuredCatalogueId &&
@@ -946,15 +622,27 @@ function useSessionValue(props) {
946
622
  return ordered;
947
623
  };
948
624
  /*
949
- * Sell codes and opening bids live on the stream record, not in the catalogue — the commerce
950
- * adapter is asked for products by id and has no idea a lot carries either. Joined on here so a
951
- * call site reads `product.sellId` and `product.baseBidPrice` instead of holding both lists and
952
- * matching them itself (`withLotFieldsFromRecord`; the opening bid since 0.9.0).
625
+ * Sell codes live on the stream record, not in the catalogue — the commerce adapter is asked for
626
+ * products by id and has no idea a lot carries one. Joined on here so a call site reads
627
+ * `product.sellId` instead of holding both lists and matching them itself.
953
628
  *
954
- * A new array only when the record has either for some lot, so an app on a gateway that issues
955
- * none keeps the adapter's own objects and the identity the memo already promised.
629
+ * A new array only when at least one code exists, so an app on a gateway that issues none keeps
630
+ * the adapter's own objects and the identity the memo already promised.
956
631
  */
957
- return (0, showLots_1.withLotFieldsFromRecord)(merge(), (_a = stream === null || stream === void 0 ? void 0 : stream.products) !== null && _a !== void 0 ? _a : []);
632
+ const base = merge();
633
+ const codes = new Map();
634
+ for (const row of (_a = stream === null || stream === void 0 ? void 0 : stream.products) !== null && _a !== void 0 ? _a : []) {
635
+ if (row.sellId)
636
+ codes.set(row.storeProductId, row.sellId);
637
+ }
638
+ if (!codes.size)
639
+ return base;
640
+ return base.map((product) => {
641
+ var _a;
642
+ return codes.has(product.storeProductId)
643
+ ? { ...product, sellId: (_a = codes.get(product.storeProductId)) !== null && _a !== void 0 ? _a : null }
644
+ : product;
645
+ });
958
646
  }, [catalogueProducts, externalProducts, storeProductIds, stream]);
959
647
  const activeProduct = (0, react_1.useMemo)(() => {
960
648
  var _a, _b, _c, _d, _e, _f;
@@ -982,10 +670,11 @@ function useSessionValue(props) {
982
670
  return null;
983
671
  return (_f = products[0]) !== null && _f !== void 0 ? _f : null;
984
672
  }, [products, state.activeStoreProductId, stream]);
985
- const multiplier = (_u = (_t = state.multiplierOverride) !== null && _t !== void 0 ? _t : stream === null || stream === void 0 ? void 0 : stream.viewerMultiplier) !== null && _u !== void 0 ? _u : 1;
673
+ const multiplier = (_o = (_m = state.multiplierOverride) !== null && _m !== void 0 ? _m : stream === null || stream === void 0 ? void 0 : stream.viewerMultiplier) !== null && _o !== void 0 ? _o : 1;
986
674
  /* Same precedence as the multiplier: the host's live word wins, the record stands until they
987
675
  give one. Both fall back rather than throw, so a stream row missing `meta` still renders. */
988
- const reactionStyle = (_w = (_v = state.reactionModeOverride) !== null && _v !== void 0 ? _v : stream === null || stream === void 0 ? void 0 : stream.reactionStyle) !== null && _w !== void 0 ? _w : 'single';
676
+ const reactionStyle = (_q = (_p = state.reactionModeOverride) !== null && _p !== void 0 ? _p : stream === null || stream === void 0 ? void 0 : stream.reactionStyle) !== null && _q !== void 0 ? _q : 'single';
677
+ const elapsedMs = (stream === null || stream === void 0 ? void 0 : stream.startedAtMs) ? Math.max(0, now - stream.startedAtMs) : 0;
989
678
  /**
990
679
  * Percentages come off the raw counts, so the multiplier cannot skew them — it inflates only the
991
680
  * total on display, exactly as the host's own dashboard does.
@@ -1063,28 +752,34 @@ function useSessionValue(props) {
1063
752
  alive = false;
1064
753
  };
1065
754
  // eslint-disable-next-line react-hooks/exhaustive-deps
1066
- }, [(_x = state.poll) === null || _x === void 0 ? void 0 : _x.pollUuid]);
755
+ }, [(_r = state.poll) === null || _r === void 0 ? void 0 : _r.pollUuid]);
1067
756
  const bindVideoView = (0, react_1.useCallback)((reactTag, force = false) => {
1068
- // Stopped because the app is away: a claim now would start it behind the app, with sound. The
1069
- // surface claims again once the app is back (`LiveVideoTarget`'s foreground re-claim).
1070
- if (stoppedWhileAwayRef.current)
757
+ // Stopped because the shopper closed the window: a claim now would start the show behind the app,
758
+ // with sound. Not `AppState.currentState` — on Android the window itself reads as `active`. The
759
+ // surface is bound once the app comes back (the foreground effect).
760
+ if (stoppedWhileAwayRef.current) {
761
+ heldBackTagRef.current = reactTag;
1071
762
  return;
763
+ }
1072
764
  liveSelling_1.liveSelling.engine
1073
765
  .bindView(reactTag, force)
1074
766
  .catch((caught) => (0, client_1.getLogger)().error(caught, { at: 'liveSession.bindView' }));
1075
767
  }, []);
1076
- /**
1077
- * Sends now — or, for a signed-in shopper whose name has not loaded, holds it until the name lands
1078
- * (L6) and resolves once it has gone out. See `HeldComments`.
1079
- */
1080
768
  const sendComment = (0, react_1.useCallback)(async (text, options) => {
769
+ var _a;
1081
770
  if (!text.trim())
1082
771
  return;
1083
- const held = heldCommentsRef.current;
1084
- if (nameResolvingRef.current && held)
1085
- return held.hold({ text, options });
1086
- await deliverComment(text, options);
1087
- }, [deliverComment]);
772
+ try {
773
+ // The host mutes by device; a per-install viewer id is the same granularity.
774
+ const deviceId = (_a = viewerIdRef.current) !== null && _a !== void 0 ? _a : (await liveSelling_1.liveSelling.viewer.id());
775
+ const own = await liveSelling_1.liveSelling.engine.sendComment(text, deviceId, options);
776
+ if (own)
777
+ dispatch({ kind: 'ownComment', comment: own });
778
+ }
779
+ catch (caught) {
780
+ (0, client_1.getLogger)().error(caught, { at: 'liveSession.sendComment' });
781
+ }
782
+ }, []);
1088
783
  const sendReaction = (0, react_1.useCallback)(async (reactionUrl) => {
1089
784
  try {
1090
785
  await liveSelling_1.liveSelling.engine.sendReaction(reactionUrl);
@@ -1195,25 +890,10 @@ function useSessionValue(props) {
1195
890
  .bindGuestHostView(reactTag)
1196
891
  .catch((caught) => (0, client_1.getLogger)().error(caught, { at: 'liveSession.bindGuestHostView' }));
1197
892
  }, []);
1198
- /**
1199
- * Saves the name and gives it to the engine NOW, not in the effect (L6).
1200
- *
1201
- * The caller's next line is the comment that prompted for the name. The effect that pushes the name
1202
- * belongs to this provider, a parent of that caller, and React runs parents' effects after
1203
- * children's — so the comment went out under the join-time name, usually "Anonymous", into the
1204
- * room and the stored history. Freckled Poppy set the engine's name itself to get round it. A name
1205
- * passed as the `viewerName` prop still wins, as it does everywhere else.
1206
- */
1207
893
  const chooseViewerName = (0, react_1.useCallback)(async (raw) => {
1208
- var _a;
1209
- // A name the show's team goes by isn't saved (0.13.0): the app says why (`isBlockedViewerName`).
1210
- if ((0, showNames_1.isBlockedViewerName)(raw, blockedNamesRef.current))
1211
- return null;
1212
894
  const saved = await liveSelling_1.liveSelling.viewer.saveName(raw);
1213
- if (saved) {
1214
- liveSelling_1.liveSelling.engine.setViewerName((_a = accountNameRef.current) !== null && _a !== void 0 ? _a : saved);
895
+ if (saved)
1215
896
  setChosenName(saved);
1216
- }
1217
897
  return saved;
1218
898
  }, []);
1219
899
  /** The speaker button, and nothing else. See `setOutputMuted` below for the other half. */
@@ -1312,51 +992,38 @@ function useSessionValue(props) {
1312
992
  * into a cart. It is also what comes back on the host's broadcast, so `isLeading` compares like
1313
993
  * with like. Null when signed out, which is exactly when bidding is not offered.
1314
994
  */
1315
- const bidderEmail = (_z = (_y = identity === null || identity === void 0 ? void 0 : identity.customerEmail) === null || _y === void 0 ? void 0 : _y.call(identity)) !== null && _z !== void 0 ? _z : null;
995
+ const bidderEmail = (_t = (_s = identity === null || identity === void 0 ? void 0 : identity.customerEmail) === null || _s === void 0 ? void 0 : _s.call(identity)) !== null && _t !== void 0 ? _t : null;
1316
996
  const bidder = (0, react_1.useMemo)(() => (bidderId ? { userId: bidderId, userName: viewerName, email: bidderEmail } : null), [bidderId, viewerName, bidderEmail]);
1317
- /**
1318
- * The hammer, with whether it is this shopper's (0.9.0): they led the round as it closed and the
1319
- * winning bid is theirs (`isYourWin`). Its own memo, so it is a new object only when the win, the
1320
- * round's last leader or the bidder change, never on a comment.
1321
- */
1322
- const lastWin = (0, react_1.useMemo)(() => state.lastWin
1323
- ? { ...state.lastWin, isYou: (0, auctionRules_1.isYourWin)(state.lastWin, state.leaderWhenRoundClosed, bidderId) }
1324
- : null, [state.lastWin, state.leaderWhenRoundClosed, bidderId]);
1325
997
  const auction = (0, react_1.useMemo)(() => {
1326
998
  var _a, _b, _c, _d, _e, _f, _g;
1327
- // Falls back to the lot's opening bid, else its bid step, else the show's (`openingBidFor`): until
1328
- // the first bid lands the host sends no next bid, and a slide-to-bid showing zero is worse than useless.
1329
- const nextBid = state.nextBid || (0, auctionRules_1.openingBidFor)(biddingLot, stream);
999
+ // Falls back to the lot's opening price: until the first bid lands the host sends no next bid,
1000
+ // and a slide-to-bid showing zero is worse than useless.
1001
+ const nextBid = state.nextBid || (biddingLot === null || biddingLot === void 0 ? void 0 : biddingLot.baseBidPrice) || 0;
1330
1002
  return {
1331
1003
  biddingOpen: state.biddingOpen,
1332
1004
  highestBid: state.highestBid,
1333
1005
  nextBid,
1334
- // A moment, not a countdown: it changes only when the host moves the deadline, so the session
1335
- // never ticks. A component counts down to it itself (`useAuctionCountdown`).
1336
- closesAt: (0, session_1.roundClosesAt)(state),
1006
+ timeLeftMs: (0, session_1.timeLeftMs)(state, auctionNow),
1337
1007
  isLeading: !!bidder && ((_a = state.bidLeader) === null || _a === void 0 ? void 0 : _a.userId) === bidder.userId,
1338
1008
  leaderName: (_c = (_b = state.bidLeader) === null || _b === void 0 ? void 0 : _b.userName) !== null && _c !== void 0 ? _c : null,
1339
1009
  extended: state.auctionExtended,
1340
1010
  storeProductId: (_e = (_d = state.biddingStoreProductId) !== null && _d !== void 0 ? _d : biddingLot === null || biddingLot === void 0 ? void 0 : biddingLot.storeProductId) !== null && _e !== void 0 ? _e : null,
1341
- lastWin,
1011
+ lastWin: state.lastWin,
1342
1012
  bidCap: (_f = stream === null || stream === void 0 ? void 0 : stream.bidCap) !== null && _f !== void 0 ? _f : null,
1343
1013
  extendedBiddingMs: (_g = stream === null || stream === void 0 ? void 0 : stream.extendedBiddingMs) !== null && _g !== void 0 ? _g : 0,
1344
- wonLotIds: state.wonLotIds,
1345
1014
  };
1346
- }, [state, biddingLot, bidder, stream, lastWin]);
1015
+ }, [state, auctionNow, biddingLot, bidder, stream]);
1347
1016
  const giveaway = (0, react_1.useMemo)(() => {
1348
- const drawn = state.giveawayResult;
1349
- /**
1350
- * The draw, with this shopper's part in it (0.9.0): whether they had entered (kept past the draw,
1351
- * as `registered` goes when it lands) and whether they won: by the customer id the record names on
1352
- * this draw's giveaway when a read has it, else by name among those who entered.
1353
- */
1354
- const youEntered = !!drawn && !!bidderId && drawn.enteredBy === bidderId;
1355
- const winnerId = drawn && stream ? (0, giveawayRoster_1.winnerIdFromRecord)(stream.giveaways, drawn.storeProductId, drawn.startedAtMs) : null;
1017
+ var _a, _b;
1018
+ const result = state.giveawayResult;
1019
+ // Entrant names come off the record's roster rather than the event, which carries only the
1020
+ // winner. A draw the record has not caught up with still celebrates, with fewer names in it.
1021
+ const settled = result
1022
+ ? stream === null || stream === void 0 ? void 0 : stream.giveaways.find((item) => item.storeProductId === result.storeProductId && item.status === 'ended')
1023
+ : undefined;
1356
1024
  return {
1357
- // The open giveaway for the lot, not an earlier one of the same product (`giveawayForLot`).
1358
- active: state.giveawayStoreProductId && stream
1359
- ? (0, giveawayRoster_1.giveawayForLot)(stream.giveaways, state.giveawayStoreProductId)
1025
+ active: state.giveawayStoreProductId
1026
+ ? ((_a = stream === null || stream === void 0 ? void 0 : stream.giveaways.find((item) => item.storeProductId === state.giveawayStoreProductId)) !== null && _a !== void 0 ? _a : null)
1360
1027
  : null,
1361
1028
  // Inflated by the host's multiplier, exactly as `viewerCount` and poll totals are. State keeps
1362
1029
  // the raw count; only the read out of the session multiplies.
@@ -1367,21 +1034,8 @@ function useSessionValue(props) {
1367
1034
  * still active and a re-render to fire.
1368
1035
  */
1369
1036
  registered: !!bidderId && state.giveawayRegisteredBy === bidderId,
1370
- /* The roster is held in the reducer once known, so a later read cannot change it mid-reveal. */
1371
- result: drawn
1372
- ? {
1373
- winnerName: drawn.winnerName,
1374
- entrantNames: drawn.entrantNames,
1375
- entrantNamesReady: drawn.entrantNamesReady,
1376
- youEntered,
1377
- isYou: (0, giveawayRoster_1.isYourGiveawayWin)({
1378
- winnerId,
1379
- winnerName: drawn.winnerName,
1380
- youEntered,
1381
- bidderId,
1382
- viewerName: namedBy,
1383
- }),
1384
- }
1037
+ result: result
1038
+ ? { winnerName: result.winnerName, entrantNames: (_b = settled === null || settled === void 0 ? void 0 : settled.entrantNames) !== null && _b !== void 0 ? _b : [] }
1385
1039
  : null,
1386
1040
  };
1387
1041
  }, [
@@ -1392,7 +1046,6 @@ function useSessionValue(props) {
1392
1046
  state.giveawayResult,
1393
1047
  stream,
1394
1048
  multiplier,
1395
- namedBy,
1396
1049
  ]);
1397
1050
  /**
1398
1051
  * The round, the stream and the bidder, for the actions to read when they fire.
@@ -1429,13 +1082,11 @@ function useSessionValue(props) {
1429
1082
  const round = roundRef.current;
1430
1083
  const current = streamRef.current;
1431
1084
  const who = bidderRef.current;
1432
- if (!current)
1433
- return { sent: false, reason: 'noShow' };
1434
- if (!who)
1435
- return { sent: false, reason: 'signedOut' };
1085
+ if (!current || !who)
1086
+ return;
1436
1087
  const amount = (_a = options === null || options === void 0 ? void 0 : options.amount) !== null && _a !== void 0 ? _a : round.auction.nextBid;
1437
1088
  if (!amount || amount <= 0)
1438
- return { sent: false, reason: 'noAmount' };
1089
+ return;
1439
1090
  /**
1440
1091
  * The lot's only variant, for a bid that names none.
1441
1092
  *
@@ -1452,20 +1103,6 @@ function useSessionValue(props) {
1452
1103
  */
1453
1104
  const lot = productsRef.current.find((product) => product.storeProductId === round.auction.storeProductId);
1454
1105
  const soleVariantId = (lot === null || lot === void 0 ? void 0 : lot.variants.length) === 1 ? ((_c = (_b = lot.variants[0]) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : null) : null;
1455
- /**
1456
- * No moderator, no bid (L3). Bids go to the moderator in charge and to nobody else, and a viewer
1457
- * who missed the round's opening may not know one — see `lastModeratorId`. Said rather than
1458
- * swallowed, and the ledger is left alone: before 0.9.0 the REST record still went out, for a bid
1459
- * that never entered the round.
1460
- */
1461
- if (!round.moderatorId) {
1462
- (0, client_1.logWarning)(new Error('No moderator is known for this round, so the bid was not sent'), {
1463
- at: 'liveSession.placeBid',
1464
- amount,
1465
- });
1466
- return { sent: false, reason: 'noModerator' };
1467
- }
1468
- let result = { sent: true };
1469
1106
  try {
1470
1107
  await liveSelling_1.liveSelling.engine.sendBid({
1471
1108
  bidAmount: amount,
@@ -1479,7 +1116,6 @@ function useSessionValue(props) {
1479
1116
  }
1480
1117
  catch (caught) {
1481
1118
  (0, client_1.getLogger)().error(caught, { at: 'liveSession.placeBid', amount });
1482
- result = { sent: false, reason: 'sendFailed' };
1483
1119
  }
1484
1120
  try {
1485
1121
  await liveSelling_1.liveSelling.auctions.recordBid({
@@ -1493,17 +1129,14 @@ function useSessionValue(props) {
1493
1129
  catch (caught) {
1494
1130
  (0, client_1.getLogger)().error(caught, { at: 'liveSession.recordBid', amount });
1495
1131
  }
1496
- return result;
1497
1132
  }, []);
1498
1133
  const enterGiveaway = (0, react_1.useCallback)(async (cartId) => {
1499
1134
  var _a, _b, _c;
1500
1135
  const lot = giveawayLotRef.current;
1501
1136
  const current = streamRef.current;
1502
1137
  const customer = customerRefRef.current;
1503
- if (!current || !lot)
1504
- return { entered: false, reason: 'noGiveaway' };
1505
- if (!customer)
1506
- return { entered: false, reason: 'signedOut' };
1138
+ if (!current || !lot || !customer)
1139
+ return;
1507
1140
  try {
1508
1141
  const viewerId = (_a = viewerIdRef.current) !== null && _a !== void 0 ? _a : (await liveSelling_1.liveSelling.viewer.id());
1509
1142
  const entered = await liveSelling_1.liveSelling.auctions.enterGiveaway({
@@ -1516,14 +1149,11 @@ function useSessionValue(props) {
1516
1149
  });
1517
1150
  // Only on the host's confirmation. The entry count follows from its own push, so nothing here
1518
1151
  // guesses at it.
1519
- if (!entered)
1520
- return { entered: false, reason: 'refused' };
1521
- dispatch({ kind: 'giveawayRegistered', bidderId: (_c = (_b = bidderRef.current) === null || _b === void 0 ? void 0 : _b.userId) !== null && _c !== void 0 ? _c : null });
1522
- return { entered: true };
1152
+ if (entered)
1153
+ dispatch({ kind: 'giveawayRegistered', bidderId: (_c = (_b = bidderRef.current) === null || _b === void 0 ? void 0 : _b.userId) !== null && _c !== void 0 ? _c : null });
1523
1154
  }
1524
1155
  catch (caught) {
1525
1156
  (0, client_1.getLogger)().error(caught, { at: 'liveSession.enterGiveaway' });
1526
- return { entered: false, reason: 'failed' };
1527
1157
  }
1528
1158
  }, []);
1529
1159
  const dismissAuctionWin = (0, react_1.useCallback)(() => dispatch({ kind: 'dismissWin' }), []);
@@ -1580,35 +1210,10 @@ function useSessionValue(props) {
1580
1210
  dismissAuctionWin,
1581
1211
  dismissGiveawayResult,
1582
1212
  ]);
1583
- const guest = (0, react_1.useMemo)(() => ({
1584
- mode: state.guestMode,
1585
- status: state.guestStatus,
1586
- slot: state.guestSlot,
1587
- mutedByHost: state.guestMutedByHost,
1588
- cameraOffByHost: state.guestCameraOffByHost,
1589
- mixerLayout: state.mixerLayout,
1590
- }), [
1591
- state.guestMode,
1592
- state.guestStatus,
1593
- state.guestSlot,
1594
- state.guestMutedByHost,
1595
- state.guestCameraOffByHost,
1596
- state.mixerLayout,
1597
- ]);
1598
- const viewerCount = Math.round(state.rawViewerCount * multiplier);
1599
- const pinnedComment = status === 'ended' ? null : state.pinnedComment;
1600
- /**
1601
- * The same object until one of its fields changes.
1602
- *
1603
- * Every component that reads the session is drawn again when this object changes, and the session is
1604
- * app-wide. Built fresh on every render, it changed whenever the provider was drawn for any reason —
1605
- * its parent passing the same props again, a record read that changed nothing a reader sees — and
1606
- * drew every reader with it. Field by field, so a new object means something in it is new.
1607
- */
1608
- return (0, react_1.useMemo)(() => ({
1213
+ return {
1609
1214
  status,
1610
1215
  stream: stream !== null && stream !== void 0 ? stream : null,
1611
- viewerCount,
1216
+ viewerCount: Math.round(state.rawViewerCount * multiplier),
1612
1217
  rawViewerCount: state.rawViewerCount,
1613
1218
  reactionStyle,
1614
1219
  comments: state.comments,
@@ -1619,39 +1224,23 @@ function useSessionValue(props) {
1619
1224
  reactions: state.reactions,
1620
1225
  poll,
1621
1226
  viewerName: namedBy,
1622
- guest,
1227
+ guest: {
1228
+ mode: state.guestMode,
1229
+ status: state.guestStatus,
1230
+ slot: state.guestSlot,
1231
+ mutedByHost: state.guestMutedByHost,
1232
+ cameraOffByHost: state.guestCameraOffByHost,
1233
+ mixerLayout: state.mixerLayout,
1234
+ },
1623
1235
  muted,
1624
1236
  videoTag: state.videoTag,
1237
+ elapsedMs,
1625
1238
  pipMode,
1626
1239
  auction,
1627
1240
  giveaway,
1628
- pinnedComment,
1629
- error,
1630
- actions,
1631
- }), [
1632
- status,
1633
- stream,
1634
- viewerCount,
1635
- state.rawViewerCount,
1636
- reactionStyle,
1637
- state.comments,
1638
- activeProduct,
1639
- products,
1640
- state.sold,
1641
- state.cartAnnouncements,
1642
- state.reactions,
1643
- poll,
1644
- namedBy,
1645
- guest,
1646
- muted,
1647
- state.videoTag,
1648
- pipMode,
1649
- auction,
1650
- giveaway,
1651
- pinnedComment,
1652
1241
  error,
1653
1242
  actions,
1654
- ]);
1243
+ };
1655
1244
  }
1656
1245
  /**
1657
1246
  * Holds one live session for the whole app. Nothing is joined while no stream is live, so the engine
@@ -1679,20 +1268,18 @@ function LiveSessionProvider({ children, ...props }) {
1679
1268
  the video — see the note on `actions` in `useSessionValue`. */
1680
1269
  const watchedRef = (0, react_1.useRef)(undefined);
1681
1270
  watchedRef.current = (_d = (_c = props.streamingId) !== null && _c !== void 0 ? _c : heldId) !== null && _d !== void 0 ? _d : (_e = session.stream) === null || _e === void 0 ? void 0 : _e.streamingId;
1682
- const holdStream = (0, react_1.useCallback)((streamingId) => {
1683
- /* A named show wins over whatever is on screen — see `holdStream` in `LiveSessionActions`. With
1684
- none named and nothing to pin yet, the caller retries when a stream id arrives, so a player
1685
- opened before the read resolved is not left following whatever turns up next. */
1686
- const id = streamingId || watchedRef.current;
1271
+ const holdStream = (0, react_1.useCallback)(() => {
1272
+ /* Nothing to pin yet — the caller retries when a stream id arrives, so a player opened before
1273
+ the read resolved is not left following whatever turns up next. */
1274
+ const id = watchedRef.current;
1687
1275
  if (id)
1688
1276
  setHeldId(id);
1689
1277
  }, []);
1690
1278
  const releaseStream = (0, react_1.useCallback)(() => setHeldId(null), []);
1691
- /* Two memos, and the split matters: `session` changes with every event, so folding the actions into
1692
- the same one would rebuild `actions` on every event too — the exact thing the note in
1279
+ /* Two memos, and the split matters: `session` is a fresh object every render, so folding the
1280
+ actions into the same one would rebuild `actions` every render too — the exact thing the note in
1693
1281
  `useSessionValue` warns about, and it live-locks a player that calls `holdStream` from an effect
1694
- keyed on `actions`. `session.actions` is stable, so keyed on that this one is as well. `session`
1695
- is the same object while nothing in it changed, so `value` is too: no reader is drawn for nothing. */
1282
+ keyed on `actions`. `session.actions` is stable, so keyed on that this one is as well. */
1696
1283
  const actions = (0, react_1.useMemo)(() => ({ ...session.actions, holdStream, releaseStream }), [session.actions, holdStream, releaseStream]);
1697
1284
  const value = (0, react_1.useMemo)(() => ({ ...session, actions }), [session, actions]);
1698
1285
  return (0, react_1.createElement)(LiveSessionContext.Provider, { value }, children);