@towns-protocol/sdk 0.0.191

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 (770) hide show
  1. package/README.md +29 -0
  2. package/dist/check.d.ts +31 -0
  3. package/dist/check.d.ts.map +1 -0
  4. package/dist/check.js +44 -0
  5. package/dist/check.js.map +1 -0
  6. package/dist/client.d.ts +333 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +1767 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/clientDecryptionExtensions.d.ts +44 -0
  11. package/dist/clientDecryptionExtensions.d.ts.map +1 -0
  12. package/dist/clientDecryptionExtensions.js +256 -0
  13. package/dist/clientDecryptionExtensions.js.map +1 -0
  14. package/dist/crypto_utils.d.ts +15 -0
  15. package/dist/crypto_utils.d.ts.map +1 -0
  16. package/dist/crypto_utils.js +99 -0
  17. package/dist/crypto_utils.js.map +1 -0
  18. package/dist/encryptedContentTypes.d.ts +31 -0
  19. package/dist/encryptedContentTypes.d.ts.map +1 -0
  20. package/dist/encryptedContentTypes.js +73 -0
  21. package/dist/encryptedContentTypes.js.map +1 -0
  22. package/dist/id.d.ts +54 -0
  23. package/dist/id.d.ts.map +1 -0
  24. package/dist/id.js +190 -0
  25. package/dist/id.js.map +1 -0
  26. package/dist/index.d.ts +101 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +101 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/makeAuthenticationRpcClient.d.ts +8 -0
  31. package/dist/makeAuthenticationRpcClient.d.ts.map +1 -0
  32. package/dist/makeAuthenticationRpcClient.js +39 -0
  33. package/dist/makeAuthenticationRpcClient.js.map +1 -0
  34. package/dist/makeNotificationRpcClient.d.ts +8 -0
  35. package/dist/makeNotificationRpcClient.d.ts.map +1 -0
  36. package/dist/makeNotificationRpcClient.js +40 -0
  37. package/dist/makeNotificationRpcClient.js.map +1 -0
  38. package/dist/makeRiverRpcClient.d.ts +6 -0
  39. package/dist/makeRiverRpcClient.d.ts.map +1 -0
  40. package/dist/makeRiverRpcClient.js +9 -0
  41. package/dist/makeRiverRpcClient.js.map +1 -0
  42. package/dist/makeStreamRpcClient.d.ts +20 -0
  43. package/dist/makeStreamRpcClient.d.ts.map +1 -0
  44. package/dist/makeStreamRpcClient.js +91 -0
  45. package/dist/makeStreamRpcClient.js.map +1 -0
  46. package/dist/memberMetadata_DisplayNames.d.ts +27 -0
  47. package/dist/memberMetadata_DisplayNames.d.ts.map +1 -0
  48. package/dist/memberMetadata_DisplayNames.js +96 -0
  49. package/dist/memberMetadata_DisplayNames.js.map +1 -0
  50. package/dist/memberMetadata_EnsAddresses.d.ts +25 -0
  51. package/dist/memberMetadata_EnsAddresses.d.ts.map +1 -0
  52. package/dist/memberMetadata_EnsAddresses.js +86 -0
  53. package/dist/memberMetadata_EnsAddresses.js.map +1 -0
  54. package/dist/memberMetadata_Nft.d.ts +31 -0
  55. package/dist/memberMetadata_Nft.d.ts.map +1 -0
  56. package/dist/memberMetadata_Nft.js +95 -0
  57. package/dist/memberMetadata_Nft.js.map +1 -0
  58. package/dist/memberMetadata_Usernames.d.ts +33 -0
  59. package/dist/memberMetadata_Usernames.d.ts.map +1 -0
  60. package/dist/memberMetadata_Usernames.js +152 -0
  61. package/dist/memberMetadata_Usernames.js.map +1 -0
  62. package/dist/migrations/migrateSnapshot.d.ts +3 -0
  63. package/dist/migrations/migrateSnapshot.d.ts.map +1 -0
  64. package/dist/migrations/migrateSnapshot.js +17 -0
  65. package/dist/migrations/migrateSnapshot.js.map +1 -0
  66. package/dist/migrations/snapshotMigration0000.d.ts +3 -0
  67. package/dist/migrations/snapshotMigration0000.d.ts.map +1 -0
  68. package/dist/migrations/snapshotMigration0000.js +5 -0
  69. package/dist/migrations/snapshotMigration0000.js.map +1 -0
  70. package/dist/migrations/snapshotMigration0001.d.ts +3 -0
  71. package/dist/migrations/snapshotMigration0001.d.ts.map +1 -0
  72. package/dist/migrations/snapshotMigration0001.js +40 -0
  73. package/dist/migrations/snapshotMigration0001.js.map +1 -0
  74. package/dist/migrations/snapshotMigration0002.d.ts +3 -0
  75. package/dist/migrations/snapshotMigration0002.d.ts.map +1 -0
  76. package/dist/migrations/snapshotMigration0002.js +23 -0
  77. package/dist/migrations/snapshotMigration0002.js.map +1 -0
  78. package/dist/notificationService.d.ts +17 -0
  79. package/dist/notificationService.d.ts.map +1 -0
  80. package/dist/notificationService.js +48 -0
  81. package/dist/notificationService.js.map +1 -0
  82. package/dist/observable/observable.d.ts +28 -0
  83. package/dist/observable/observable.d.ts.map +1 -0
  84. package/dist/observable/observable.js +57 -0
  85. package/dist/observable/observable.js.map +1 -0
  86. package/dist/observable/persistedObservable.d.ts +37 -0
  87. package/dist/observable/persistedObservable.d.ts.map +1 -0
  88. package/dist/observable/persistedObservable.js +77 -0
  89. package/dist/observable/persistedObservable.js.map +1 -0
  90. package/dist/persistenceStore.d.ts +71 -0
  91. package/dist/persistenceStore.d.ts.map +1 -0
  92. package/dist/persistenceStore.js +366 -0
  93. package/dist/persistenceStore.js.map +1 -0
  94. package/dist/riverConfig.d.ts +23 -0
  95. package/dist/riverConfig.d.ts.map +1 -0
  96. package/dist/riverConfig.js +111 -0
  97. package/dist/riverConfig.js.map +1 -0
  98. package/dist/riverDbManager.d.ts +5 -0
  99. package/dist/riverDbManager.d.ts.map +1 -0
  100. package/dist/riverDbManager.js +7 -0
  101. package/dist/riverDbManager.js.map +1 -0
  102. package/dist/rpcCommon.d.ts +9 -0
  103. package/dist/rpcCommon.d.ts.map +1 -0
  104. package/dist/rpcCommon.js +14 -0
  105. package/dist/rpcCommon.js.map +1 -0
  106. package/dist/rpcInterceptors.d.ts +20 -0
  107. package/dist/rpcInterceptors.d.ts.map +1 -0
  108. package/dist/rpcInterceptors.js +369 -0
  109. package/dist/rpcInterceptors.js.map +1 -0
  110. package/dist/sign.d.ts +41 -0
  111. package/dist/sign.d.ts.map +1 -0
  112. package/dist/sign.js +268 -0
  113. package/dist/sign.js.map +1 -0
  114. package/dist/signerContext.d.ts +60 -0
  115. package/dist/signerContext.d.ts.map +1 -0
  116. package/dist/signerContext.js +101 -0
  117. package/dist/signerContext.js.map +1 -0
  118. package/dist/store/store.d.ts +22 -0
  119. package/dist/store/store.d.ts.map +1 -0
  120. package/dist/store/store.js +165 -0
  121. package/dist/store/store.js.map +1 -0
  122. package/dist/stream.d.ts +47 -0
  123. package/dist/stream.d.ts.map +1 -0
  124. package/dist/stream.js +111 -0
  125. package/dist/stream.js.map +1 -0
  126. package/dist/streamEvents.d.ts +86 -0
  127. package/dist/streamEvents.d.ts.map +1 -0
  128. package/dist/streamEvents.js +2 -0
  129. package/dist/streamEvents.js.map +1 -0
  130. package/dist/streamStateView.d.ts +119 -0
  131. package/dist/streamStateView.d.ts.map +1 -0
  132. package/dist/streamStateView.js +527 -0
  133. package/dist/streamStateView.js.map +1 -0
  134. package/dist/streamStateView_AbstractContent.d.ts +20 -0
  135. package/dist/streamStateView_AbstractContent.d.ts.map +1 -0
  136. package/dist/streamStateView_AbstractContent.js +41 -0
  137. package/dist/streamStateView_AbstractContent.js.map +1 -0
  138. package/dist/streamStateView_Channel.d.ts +20 -0
  139. package/dist/streamStateView_Channel.d.ts.map +1 -0
  140. package/dist/streamStateView_Channel.js +65 -0
  141. package/dist/streamStateView_Channel.js.map +1 -0
  142. package/dist/streamStateView_ChannelMetadata.d.ts +22 -0
  143. package/dist/streamStateView_ChannelMetadata.d.ts.map +1 -0
  144. package/dist/streamStateView_ChannelMetadata.js +57 -0
  145. package/dist/streamStateView_ChannelMetadata.js.map +1 -0
  146. package/dist/streamStateView_DMChannel.d.ts +22 -0
  147. package/dist/streamStateView_DMChannel.d.ts.map +1 -0
  148. package/dist/streamStateView_DMChannel.js +78 -0
  149. package/dist/streamStateView_DMChannel.js.map +1 -0
  150. package/dist/streamStateView_GDMChannel.d.ts +22 -0
  151. package/dist/streamStateView_GDMChannel.d.ts.map +1 -0
  152. package/dist/streamStateView_GDMChannel.js +82 -0
  153. package/dist/streamStateView_GDMChannel.js.map +1 -0
  154. package/dist/streamStateView_Media.d.ts +20 -0
  155. package/dist/streamStateView_Media.d.ts.map +1 -0
  156. package/dist/streamStateView_Media.js +54 -0
  157. package/dist/streamStateView_Media.js.map +1 -0
  158. package/dist/streamStateView_MemberMetadata.d.ts +51 -0
  159. package/dist/streamStateView_MemberMetadata.d.ts.map +1 -0
  160. package/dist/streamStateView_MemberMetadata.js +97 -0
  161. package/dist/streamStateView_MemberMetadata.js.map +1 -0
  162. package/dist/streamStateView_Members.d.ts +70 -0
  163. package/dist/streamStateView_Members.d.ts.map +1 -0
  164. package/dist/streamStateView_Members.js +409 -0
  165. package/dist/streamStateView_Members.js.map +1 -0
  166. package/dist/streamStateView_Members_Membership.d.ts +29 -0
  167. package/dist/streamStateView_Members_Membership.d.ts.map +1 -0
  168. package/dist/streamStateView_Members_Membership.js +117 -0
  169. package/dist/streamStateView_Members_Membership.js.map +1 -0
  170. package/dist/streamStateView_Members_Solicitations.d.ts +15 -0
  171. package/dist/streamStateView_Members_Solicitations.d.ts.map +1 -0
  172. package/dist/streamStateView_Members_Solicitations.js +49 -0
  173. package/dist/streamStateView_Members_Solicitations.js.map +1 -0
  174. package/dist/streamStateView_Space.d.ts +34 -0
  175. package/dist/streamStateView_Space.d.ts.map +1 -0
  176. package/dist/streamStateView_Space.js +190 -0
  177. package/dist/streamStateView_Space.js.map +1 -0
  178. package/dist/streamStateView_UnknownContent.d.ts +11 -0
  179. package/dist/streamStateView_UnknownContent.d.ts.map +1 -0
  180. package/dist/streamStateView_UnknownContent.js +15 -0
  181. package/dist/streamStateView_UnknownContent.js.map +1 -0
  182. package/dist/streamStateView_User.d.ts +26 -0
  183. package/dist/streamStateView_User.d.ts.map +1 -0
  184. package/dist/streamStateView_User.js +154 -0
  185. package/dist/streamStateView_User.js.map +1 -0
  186. package/dist/streamStateView_UserInbox.d.ts +17 -0
  187. package/dist/streamStateView_UserInbox.d.ts.map +1 -0
  188. package/dist/streamStateView_UserInbox.js +70 -0
  189. package/dist/streamStateView_UserInbox.js.map +1 -0
  190. package/dist/streamStateView_UserMetadata.d.ts +27 -0
  191. package/dist/streamStateView_UserMetadata.d.ts.map +1 -0
  192. package/dist/streamStateView_UserMetadata.js +146 -0
  193. package/dist/streamStateView_UserMetadata.js.map +1 -0
  194. package/dist/streamStateView_UserSettings.d.ts +32 -0
  195. package/dist/streamStateView_UserSettings.d.ts.map +1 -0
  196. package/dist/streamStateView_UserSettings.js +112 -0
  197. package/dist/streamStateView_UserSettings.js.map +1 -0
  198. package/dist/streamUtils.d.ts +15 -0
  199. package/dist/streamUtils.d.ts.map +1 -0
  200. package/dist/streamUtils.js +112 -0
  201. package/dist/streamUtils.js.map +1 -0
  202. package/dist/sync-agent/db.d.ts +19 -0
  203. package/dist/sync-agent/db.d.ts.map +1 -0
  204. package/dist/sync-agent/db.js +36 -0
  205. package/dist/sync-agent/db.js.map +1 -0
  206. package/dist/sync-agent/dms/dms.d.ts +24 -0
  207. package/dist/sync-agent/dms/dms.d.ts.map +1 -0
  208. package/dist/sync-agent/dms/dms.js +60 -0
  209. package/dist/sync-agent/dms/dms.js.map +1 -0
  210. package/dist/sync-agent/dms/models/dm.d.ts +59 -0
  211. package/dist/sync-agent/dms/models/dm.d.ts.map +1 -0
  212. package/dist/sync-agent/dms/models/dm.js +140 -0
  213. package/dist/sync-agent/dms/models/dm.js.map +1 -0
  214. package/dist/sync-agent/entitlements/entitlements.d.ts +10 -0
  215. package/dist/sync-agent/entitlements/entitlements.d.ts.map +1 -0
  216. package/dist/sync-agent/entitlements/entitlements.js +23 -0
  217. package/dist/sync-agent/entitlements/entitlements.js.map +1 -0
  218. package/dist/sync-agent/gdms/gdms.d.ts +23 -0
  219. package/dist/sync-agent/gdms/gdms.d.ts.map +1 -0
  220. package/dist/sync-agent/gdms/gdms.js +56 -0
  221. package/dist/sync-agent/gdms/gdms.js.map +1 -0
  222. package/dist/sync-agent/gdms/models/gdm.d.ts +59 -0
  223. package/dist/sync-agent/gdms/models/gdm.d.ts.map +1 -0
  224. package/dist/sync-agent/gdms/models/gdm.js +138 -0
  225. package/dist/sync-agent/gdms/models/gdm.js.map +1 -0
  226. package/dist/sync-agent/members/members.d.ts +32 -0
  227. package/dist/sync-agent/members/members.d.ts.map +1 -0
  228. package/dist/sync-agent/members/members.js +143 -0
  229. package/dist/sync-agent/members/members.js.map +1 -0
  230. package/dist/sync-agent/members/models/member.d.ts +66 -0
  231. package/dist/sync-agent/members/models/member.d.ts.map +1 -0
  232. package/dist/sync-agent/members/models/member.js +131 -0
  233. package/dist/sync-agent/members/models/member.js.map +1 -0
  234. package/dist/sync-agent/members/models/myself.d.ts +20 -0
  235. package/dist/sync-agent/members/models/myself.d.ts.map +1 -0
  236. package/dist/sync-agent/members/models/myself.js +97 -0
  237. package/dist/sync-agent/members/models/myself.js.map +1 -0
  238. package/dist/sync-agent/river-connection/models/authStatus.d.ts +18 -0
  239. package/dist/sync-agent/river-connection/models/authStatus.d.ts.map +1 -0
  240. package/dist/sync-agent/river-connection/models/authStatus.js +19 -0
  241. package/dist/sync-agent/river-connection/models/authStatus.js.map +1 -0
  242. package/dist/sync-agent/river-connection/models/riverChain.d.ts +30 -0
  243. package/dist/sync-agent/river-connection/models/riverChain.d.ts.map +1 -0
  244. package/dist/sync-agent/river-connection/models/riverChain.js +93 -0
  245. package/dist/sync-agent/river-connection/models/riverChain.js.map +1 -0
  246. package/dist/sync-agent/river-connection/models/transactionalClient.d.ts +11 -0
  247. package/dist/sync-agent/river-connection/models/transactionalClient.d.ts.map +1 -0
  248. package/dist/sync-agent/river-connection/models/transactionalClient.js +14 -0
  249. package/dist/sync-agent/river-connection/models/transactionalClient.js.map +1 -0
  250. package/dist/sync-agent/river-connection/riverConnection.d.ts +61 -0
  251. package/dist/sync-agent/river-connection/riverConnection.d.ts.map +1 -0
  252. package/dist/sync-agent/river-connection/riverConnection.js +229 -0
  253. package/dist/sync-agent/river-connection/riverConnection.js.map +1 -0
  254. package/dist/sync-agent/spaces/models/channel.d.ts +84 -0
  255. package/dist/sync-agent/spaces/models/channel.d.ts.map +1 -0
  256. package/dist/sync-agent/spaces/models/channel.js +173 -0
  257. package/dist/sync-agent/spaces/models/channel.js.map +1 -0
  258. package/dist/sync-agent/spaces/models/space.d.ts +57 -0
  259. package/dist/sync-agent/spaces/models/space.d.ts.map +1 -0
  260. package/dist/sync-agent/spaces/models/space.js +147 -0
  261. package/dist/sync-agent/spaces/models/space.js.map +1 -0
  262. package/dist/sync-agent/spaces/spaces.d.ts +29 -0
  263. package/dist/sync-agent/spaces/spaces.d.ts.map +1 -0
  264. package/dist/sync-agent/spaces/spaces.js +90 -0
  265. package/dist/sync-agent/spaces/spaces.js.map +1 -0
  266. package/dist/sync-agent/syncAgent.d.ts +68 -0
  267. package/dist/sync-agent/syncAgent.d.ts.map +1 -0
  268. package/dist/sync-agent/syncAgent.js +108 -0
  269. package/dist/sync-agent/syncAgent.js.map +1 -0
  270. package/dist/sync-agent/timeline/models/pendingReplacedEvents.d.ts +12 -0
  271. package/dist/sync-agent/timeline/models/pendingReplacedEvents.d.ts.map +1 -0
  272. package/dist/sync-agent/timeline/models/pendingReplacedEvents.js +20 -0
  273. package/dist/sync-agent/timeline/models/pendingReplacedEvents.js.map +1 -0
  274. package/dist/sync-agent/timeline/models/reactions.d.ts +13 -0
  275. package/dist/sync-agent/timeline/models/reactions.d.ts.map +1 -0
  276. package/dist/sync-agent/timeline/models/reactions.js +67 -0
  277. package/dist/sync-agent/timeline/models/reactions.js.map +1 -0
  278. package/dist/sync-agent/timeline/models/replacedEvents.d.ts +18 -0
  279. package/dist/sync-agent/timeline/models/replacedEvents.d.ts.map +1 -0
  280. package/dist/sync-agent/timeline/models/replacedEvents.js +19 -0
  281. package/dist/sync-agent/timeline/models/replacedEvents.js.map +1 -0
  282. package/dist/sync-agent/timeline/models/threadStats.d.ts +13 -0
  283. package/dist/sync-agent/timeline/models/threadStats.d.ts.map +1 -0
  284. package/dist/sync-agent/timeline/models/threadStats.js +99 -0
  285. package/dist/sync-agent/timeline/models/threadStats.js.map +1 -0
  286. package/dist/sync-agent/timeline/models/threads.d.ts +14 -0
  287. package/dist/sync-agent/timeline/models/threads.d.ts.map +1 -0
  288. package/dist/sync-agent/timeline/models/threads.js +57 -0
  289. package/dist/sync-agent/timeline/models/threads.js.map +1 -0
  290. package/dist/sync-agent/timeline/models/timeline-types.d.ts +364 -0
  291. package/dist/sync-agent/timeline/models/timeline-types.d.ts.map +1 -0
  292. package/dist/sync-agent/timeline/models/timeline-types.js +66 -0
  293. package/dist/sync-agent/timeline/models/timeline-types.js.map +1 -0
  294. package/dist/sync-agent/timeline/models/timelineEvent.d.ts +14 -0
  295. package/dist/sync-agent/timeline/models/timelineEvent.d.ts.map +1 -0
  296. package/dist/sync-agent/timeline/models/timelineEvent.js +1080 -0
  297. package/dist/sync-agent/timeline/models/timelineEvent.js.map +1 -0
  298. package/dist/sync-agent/timeline/models/timelineEvents.d.ts +13 -0
  299. package/dist/sync-agent/timeline/models/timelineEvents.d.ts.map +1 -0
  300. package/dist/sync-agent/timeline/models/timelineEvents.js +37 -0
  301. package/dist/sync-agent/timeline/models/timelineEvents.js.map +1 -0
  302. package/dist/sync-agent/timeline/timeline.d.ts +43 -0
  303. package/dist/sync-agent/timeline/timeline.d.ts.map +1 -0
  304. package/dist/sync-agent/timeline/timeline.js +246 -0
  305. package/dist/sync-agent/timeline/timeline.js.map +1 -0
  306. package/dist/sync-agent/user/models/userInbox.d.ts +21 -0
  307. package/dist/sync-agent/user/models/userInbox.d.ts.map +1 -0
  308. package/dist/sync-agent/user/models/userInbox.js +68 -0
  309. package/dist/sync-agent/user/models/userInbox.js.map +1 -0
  310. package/dist/sync-agent/user/models/userMemberships.d.ts +29 -0
  311. package/dist/sync-agent/user/models/userMemberships.d.ts.map +1 -0
  312. package/dist/sync-agent/user/models/userMemberships.js +84 -0
  313. package/dist/sync-agent/user/models/userMemberships.js.map +1 -0
  314. package/dist/sync-agent/user/models/userMetadata.d.ts +21 -0
  315. package/dist/sync-agent/user/models/userMetadata.d.ts.map +1 -0
  316. package/dist/sync-agent/user/models/userMetadata.js +68 -0
  317. package/dist/sync-agent/user/models/userMetadata.js.map +1 -0
  318. package/dist/sync-agent/user/models/userSettings.d.ts +17 -0
  319. package/dist/sync-agent/user/models/userSettings.d.ts.map +1 -0
  320. package/dist/sync-agent/user/models/userSettings.js +48 -0
  321. package/dist/sync-agent/user/models/userSettings.js.map +1 -0
  322. package/dist/sync-agent/user/user.d.ts +18 -0
  323. package/dist/sync-agent/user/user.d.ts.map +1 -0
  324. package/dist/sync-agent/user/user.js +30 -0
  325. package/dist/sync-agent/user/user.js.map +1 -0
  326. package/dist/sync-agent/utils/bot.d.ts +16 -0
  327. package/dist/sync-agent/utils/bot.d.ts.map +1 -0
  328. package/dist/sync-agent/utils/bot.js +39 -0
  329. package/dist/sync-agent/utils/bot.js.map +1 -0
  330. package/dist/sync-agent/utils/promiseQueue.d.ts +6 -0
  331. package/dist/sync-agent/utils/promiseQueue.d.ts.map +1 -0
  332. package/dist/sync-agent/utils/promiseQueue.js +20 -0
  333. package/dist/sync-agent/utils/promiseQueue.js.map +1 -0
  334. package/dist/sync-agent/utils/providers.d.ts +5 -0
  335. package/dist/sync-agent/utils/providers.d.ts.map +1 -0
  336. package/dist/sync-agent/utils/providers.js +16 -0
  337. package/dist/sync-agent/utils/providers.js.map +1 -0
  338. package/dist/sync-agent/utils/spaceUtils.d.ts +22 -0
  339. package/dist/sync-agent/utils/spaceUtils.d.ts.map +1 -0
  340. package/dist/sync-agent/utils/spaceUtils.js +27 -0
  341. package/dist/sync-agent/utils/spaceUtils.js.map +1 -0
  342. package/dist/syncEvents.d.ts +9 -0
  343. package/dist/syncEvents.d.ts.map +1 -0
  344. package/dist/syncEvents.js +2 -0
  345. package/dist/syncEvents.js.map +1 -0
  346. package/dist/syncedStream.d.ts +22 -0
  347. package/dist/syncedStream.d.ts.map +1 -0
  348. package/dist/syncedStream.js +108 -0
  349. package/dist/syncedStream.js.map +1 -0
  350. package/dist/syncedStreams.d.ts +46 -0
  351. package/dist/syncedStreams.d.ts.map +1 -0
  352. package/dist/syncedStreams.js +116 -0
  353. package/dist/syncedStreams.js.map +1 -0
  354. package/dist/syncedStreamsExtension.d.ts +50 -0
  355. package/dist/syncedStreamsExtension.d.ts.map +1 -0
  356. package/dist/syncedStreamsExtension.js +285 -0
  357. package/dist/syncedStreamsExtension.js.map +1 -0
  358. package/dist/syncedStreamsLoop.d.ts +121 -0
  359. package/dist/syncedStreamsLoop.d.ts.map +1 -0
  360. package/dist/syncedStreamsLoop.js +781 -0
  361. package/dist/syncedStreamsLoop.js.map +1 -0
  362. package/dist/tags.d.ts +7 -0
  363. package/dist/tags.d.ts.map +1 -0
  364. package/dist/tags.js +144 -0
  365. package/dist/tags.js.map +1 -0
  366. package/dist/tests/bob_testUtils.d.ts +4 -0
  367. package/dist/tests/bob_testUtils.d.ts.map +1 -0
  368. package/dist/tests/bob_testUtils.js +159 -0
  369. package/dist/tests/bob_testUtils.js.map +1 -0
  370. package/dist/tests/multi/channelScrubbing.test.d.ts +5 -0
  371. package/dist/tests/multi/channelScrubbing.test.d.ts.map +1 -0
  372. package/dist/tests/multi/channelScrubbing.test.js +33 -0
  373. package/dist/tests/multi/channelScrubbing.test.js.map +1 -0
  374. package/dist/tests/multi/channelSpaceSettings.test.d.ts +5 -0
  375. package/dist/tests/multi/channelSpaceSettings.test.d.ts.map +1 -0
  376. package/dist/tests/multi/channelSpaceSettings.test.js +206 -0
  377. package/dist/tests/multi/channelSpaceSettings.test.js.map +1 -0
  378. package/dist/tests/multi/disableChannel.test.d.ts +5 -0
  379. package/dist/tests/multi/disableChannel.test.d.ts.map +1 -0
  380. package/dist/tests/multi/disableChannel.test.js +30 -0
  381. package/dist/tests/multi/disableChannel.test.js.map +1 -0
  382. package/dist/tests/multi/disableSpace.test.d.ts +5 -0
  383. package/dist/tests/multi/disableSpace.test.d.ts.map +1 -0
  384. package/dist/tests/multi/disableSpace.test.js +37 -0
  385. package/dist/tests/multi/disableSpace.test.js.map +1 -0
  386. package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.d.ts +5 -0
  387. package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.d.ts.map +1 -0
  388. package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.js +129 -0
  389. package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.js.map +1 -0
  390. package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.d.ts +5 -0
  391. package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.d.ts.map +1 -0
  392. package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.js +44 -0
  393. package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.js.map +1 -0
  394. package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.d.ts +5 -0
  395. package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.d.ts.map +1 -0
  396. package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.js +145 -0
  397. package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.js.map +1 -0
  398. package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.d.ts +5 -0
  399. package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.d.ts.map +1 -0
  400. package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.js +72 -0
  401. package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.js.map +1 -0
  402. package/dist/tests/multi/entitlements/channelsWithEntitlements.test.d.ts +5 -0
  403. package/dist/tests/multi/entitlements/channelsWithEntitlements.test.d.ts.map +1 -0
  404. package/dist/tests/multi/entitlements/channelsWithEntitlements.test.js +51 -0
  405. package/dist/tests/multi/entitlements/channelsWithEntitlements.test.js.map +1 -0
  406. package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.d.ts +5 -0
  407. package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.d.ts.map +1 -0
  408. package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.js +86 -0
  409. package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.js.map +1 -0
  410. package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.d.ts +5 -0
  411. package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.d.ts.map +1 -0
  412. package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.js +69 -0
  413. package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.js.map +1 -0
  414. package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.d.ts +5 -0
  415. package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.d.ts.map +1 -0
  416. package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.js +145 -0
  417. package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.js.map +1 -0
  418. package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.d.ts +5 -0
  419. package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.d.ts.map +1 -0
  420. package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.js +53 -0
  421. package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.js.map +1 -0
  422. package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.d.ts +5 -0
  423. package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.d.ts.map +1 -0
  424. package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.js +151 -0
  425. package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.js.map +1 -0
  426. package/dist/tests/multi/entitlements/spaceWithEntitlements.test.d.ts +5 -0
  427. package/dist/tests/multi/entitlements/spaceWithEntitlements.test.d.ts.map +1 -0
  428. package/dist/tests/multi/entitlements/spaceWithEntitlements.test.js +101 -0
  429. package/dist/tests/multi/entitlements/spaceWithEntitlements.test.js.map +1 -0
  430. package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.d.ts +5 -0
  431. package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.d.ts.map +1 -0
  432. package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.js +103 -0
  433. package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.js.map +1 -0
  434. package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.d.ts +5 -0
  435. package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.d.ts.map +1 -0
  436. package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.js +84 -0
  437. package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.js.map +1 -0
  438. package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.d.ts +5 -0
  439. package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.d.ts.map +1 -0
  440. package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.js +168 -0
  441. package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.js.map +1 -0
  442. package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.d.ts +5 -0
  443. package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.d.ts.map +1 -0
  444. package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.js +45 -0
  445. package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.js.map +1 -0
  446. package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.d.ts +5 -0
  447. package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.d.ts.map +1 -0
  448. package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.js +79 -0
  449. package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.js.map +1 -0
  450. package/dist/tests/multi/legacySpace.test.d.ts +5 -0
  451. package/dist/tests/multi/legacySpace.test.d.ts.map +1 -0
  452. package/dist/tests/multi/legacySpace.test.js +48 -0
  453. package/dist/tests/multi/legacySpace.test.js.map +1 -0
  454. package/dist/tests/multi/mediaWithEntitlements.test.d.ts +5 -0
  455. package/dist/tests/multi/mediaWithEntitlements.test.d.ts.map +1 -0
  456. package/dist/tests/multi/mediaWithEntitlements.test.js +152 -0
  457. package/dist/tests/multi/mediaWithEntitlements.test.js.map +1 -0
  458. package/dist/tests/multi/membershipManagement.test.d.ts +5 -0
  459. package/dist/tests/multi/membershipManagement.test.d.ts.map +1 -0
  460. package/dist/tests/multi/membershipManagement.test.js +76 -0
  461. package/dist/tests/multi/membershipManagement.test.js.map +1 -0
  462. package/dist/tests/multi/notificationService.test.d.ts +2 -0
  463. package/dist/tests/multi/notificationService.test.d.ts.map +1 -0
  464. package/dist/tests/multi/notificationService.test.js +51 -0
  465. package/dist/tests/multi/notificationService.test.js.map +1 -0
  466. package/dist/tests/multi/riverAirdropDapp.test.d.ts +5 -0
  467. package/dist/tests/multi/riverAirdropDapp.test.d.ts.map +1 -0
  468. package/dist/tests/multi/riverAirdropDapp.test.js +43 -0
  469. package/dist/tests/multi/riverAirdropDapp.test.js.map +1 -0
  470. package/dist/tests/multi/spaceDapp.test.d.ts +5 -0
  471. package/dist/tests/multi/spaceDapp.test.d.ts.map +1 -0
  472. package/dist/tests/multi/spaceDapp.test.js +59 -0
  473. package/dist/tests/multi/spaceDapp.test.js.map +1 -0
  474. package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.d.ts +2 -0
  475. package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.d.ts.map +1 -0
  476. package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.js +61 -0
  477. package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.js.map +1 -0
  478. package/dist/tests/multi/sync-agent/member-queue.test.d.ts +2 -0
  479. package/dist/tests/multi/sync-agent/member-queue.test.d.ts.map +1 -0
  480. package/dist/tests/multi/sync-agent/member-queue.test.js +46 -0
  481. package/dist/tests/multi/sync-agent/member-queue.test.js.map +1 -0
  482. package/dist/tests/multi/sync-agent/member.test.d.ts +2 -0
  483. package/dist/tests/multi/sync-agent/member.test.d.ts.map +1 -0
  484. package/dist/tests/multi/sync-agent/member.test.js +45 -0
  485. package/dist/tests/multi/sync-agent/member.test.js.map +1 -0
  486. package/dist/tests/multi/sync-agent/members.test.d.ts +2 -0
  487. package/dist/tests/multi/sync-agent/members.test.d.ts.map +1 -0
  488. package/dist/tests/multi/sync-agent/members.test.js +35 -0
  489. package/dist/tests/multi/sync-agent/members.test.js.map +1 -0
  490. package/dist/tests/multi/sync-agent/riverConnection.test.d.ts +5 -0
  491. package/dist/tests/multi/sync-agent/riverConnection.test.d.ts.map +1 -0
  492. package/dist/tests/multi/sync-agent/riverConnection.test.js +49 -0
  493. package/dist/tests/multi/sync-agent/riverConnection.test.js.map +1 -0
  494. package/dist/tests/multi/sync-agent/spaces.test.d.ts +2 -0
  495. package/dist/tests/multi/sync-agent/spaces.test.d.ts.map +1 -0
  496. package/dist/tests/multi/sync-agent/spaces.test.js +33 -0
  497. package/dist/tests/multi/sync-agent/spaces.test.js.map +1 -0
  498. package/dist/tests/multi/sync-agent/streams.test.d.ts +2 -0
  499. package/dist/tests/multi/sync-agent/streams.test.d.ts.map +1 -0
  500. package/dist/tests/multi/sync-agent/streams.test.js +27 -0
  501. package/dist/tests/multi/sync-agent/streams.test.js.map +1 -0
  502. package/dist/tests/multi/sync-agent/syncAgent.test.d.ts +2 -0
  503. package/dist/tests/multi/sync-agent/syncAgent.test.d.ts.map +1 -0
  504. package/dist/tests/multi/sync-agent/syncAgent.test.js +65 -0
  505. package/dist/tests/multi/sync-agent/syncAgent.test.js.map +1 -0
  506. package/dist/tests/multi/sync-agent/syncAgents.test.d.ts +2 -0
  507. package/dist/tests/multi/sync-agent/syncAgents.test.d.ts.map +1 -0
  508. package/dist/tests/multi/sync-agent/syncAgents.test.js +160 -0
  509. package/dist/tests/multi/sync-agent/syncAgents.test.js.map +1 -0
  510. package/dist/tests/multi/sync-agent/timeline.test.d.ts +2 -0
  511. package/dist/tests/multi/sync-agent/timeline.test.d.ts.map +1 -0
  512. package/dist/tests/multi/sync-agent/timeline.test.js +220 -0
  513. package/dist/tests/multi/sync-agent/timeline.test.js.map +1 -0
  514. package/dist/tests/multi/sync-agent/user.test.d.ts +5 -0
  515. package/dist/tests/multi/sync-agent/user.test.d.ts.map +1 -0
  516. package/dist/tests/multi/sync-agent/user.test.js +55 -0
  517. package/dist/tests/multi/sync-agent/user.test.js.map +1 -0
  518. package/dist/tests/multi/transactions.test.d.ts +5 -0
  519. package/dist/tests/multi/transactions.test.d.ts.map +1 -0
  520. package/dist/tests/multi/transactions.test.js +153 -0
  521. package/dist/tests/multi/transactions.test.js.map +1 -0
  522. package/dist/tests/multi/transactions_SpaceReview.test.d.ts +2 -0
  523. package/dist/tests/multi/transactions_SpaceReview.test.d.ts.map +1 -0
  524. package/dist/tests/multi/transactions_SpaceReview.test.js +280 -0
  525. package/dist/tests/multi/transactions_SpaceReview.test.js.map +1 -0
  526. package/dist/tests/multi/transactions_Tip.test.d.ts +5 -0
  527. package/dist/tests/multi/transactions_Tip.test.d.ts.map +1 -0
  528. package/dist/tests/multi/transactions_Tip.test.js +235 -0
  529. package/dist/tests/multi/transactions_Tip.test.js.map +1 -0
  530. package/dist/tests/multi/withEntitlements.test.d.ts +5 -0
  531. package/dist/tests/multi/withEntitlements.test.d.ts.map +1 -0
  532. package/dist/tests/multi/withEntitlements.test.js +125 -0
  533. package/dist/tests/multi/withEntitlements.test.js.map +1 -0
  534. package/dist/tests/multi_ne/aliceAndFriends.test.d.ts +5 -0
  535. package/dist/tests/multi_ne/aliceAndFriends.test.d.ts.map +1 -0
  536. package/dist/tests/multi_ne/aliceAndFriends.test.js +20 -0
  537. package/dist/tests/multi_ne/aliceAndFriends.test.js.map +1 -0
  538. package/dist/tests/multi_ne/aliceAndFriends10for10.test.d.ts +5 -0
  539. package/dist/tests/multi_ne/aliceAndFriends10for10.test.d.ts.map +1 -0
  540. package/dist/tests/multi_ne/aliceAndFriends10for10.test.js +23 -0
  541. package/dist/tests/multi_ne/aliceAndFriends10for10.test.js.map +1 -0
  542. package/dist/tests/multi_ne/aliceAndFriends3for8.test.d.ts +5 -0
  543. package/dist/tests/multi_ne/aliceAndFriends3for8.test.d.ts.map +1 -0
  544. package/dist/tests/multi_ne/aliceAndFriends3for8.test.js +22 -0
  545. package/dist/tests/multi_ne/aliceAndFriends3for8.test.js.map +1 -0
  546. package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.d.ts +5 -0
  547. package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.d.ts.map +1 -0
  548. package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.js +28 -0
  549. package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.js.map +1 -0
  550. package/dist/tests/multi_ne/bobFlushes.test.d.ts +5 -0
  551. package/dist/tests/multi_ne/bobFlushes.test.d.ts.map +1 -0
  552. package/dist/tests/multi_ne/bobFlushes.test.js +20 -0
  553. package/dist/tests/multi_ne/bobFlushes.test.js.map +1 -0
  554. package/dist/tests/multi_ne/channels.test.d.ts +5 -0
  555. package/dist/tests/multi_ne/channels.test.d.ts.map +1 -0
  556. package/dist/tests/multi_ne/channels.test.js +47 -0
  557. package/dist/tests/multi_ne/channels.test.js.map +1 -0
  558. package/dist/tests/multi_ne/client.test.d.ts +5 -0
  559. package/dist/tests/multi_ne/client.test.d.ts.map +1 -0
  560. package/dist/tests/multi_ne/client.test.js +786 -0
  561. package/dist/tests/multi_ne/client.test.js.map +1 -0
  562. package/dist/tests/multi_ne/clientCrypto.test.d.ts +5 -0
  563. package/dist/tests/multi_ne/clientCrypto.test.d.ts.map +1 -0
  564. package/dist/tests/multi_ne/clientCrypto.test.js +64 -0
  565. package/dist/tests/multi_ne/clientCrypto.test.js.map +1 -0
  566. package/dist/tests/multi_ne/clientDecryptionExtensions.test.d.ts +5 -0
  567. package/dist/tests/multi_ne/clientDecryptionExtensions.test.d.ts.map +1 -0
  568. package/dist/tests/multi_ne/clientDecryptionExtensions.test.js +174 -0
  569. package/dist/tests/multi_ne/clientDecryptionExtensions.test.js.map +1 -0
  570. package/dist/tests/multi_ne/deviceKeyMessage.test.d.ts +5 -0
  571. package/dist/tests/multi_ne/deviceKeyMessage.test.d.ts.map +1 -0
  572. package/dist/tests/multi_ne/deviceKeyMessage.test.js +154 -0
  573. package/dist/tests/multi_ne/deviceKeyMessage.test.js.map +1 -0
  574. package/dist/tests/multi_ne/dms.test.d.ts +5 -0
  575. package/dist/tests/multi_ne/dms.test.d.ts.map +1 -0
  576. package/dist/tests/multi_ne/dms.test.js +131 -0
  577. package/dist/tests/multi_ne/dms.test.js.map +1 -0
  578. package/dist/tests/multi_ne/gdms.test.d.ts +5 -0
  579. package/dist/tests/multi_ne/gdms.test.d.ts.map +1 -0
  580. package/dist/tests/multi_ne/gdms.test.js +274 -0
  581. package/dist/tests/multi_ne/gdms.test.js.map +1 -0
  582. package/dist/tests/multi_ne/id.test.d.ts +5 -0
  583. package/dist/tests/multi_ne/id.test.d.ts.map +1 -0
  584. package/dist/tests/multi_ne/id.test.js +70 -0
  585. package/dist/tests/multi_ne/id.test.js.map +1 -0
  586. package/dist/tests/multi_ne/makeStreamRpcClient.test.d.ts +5 -0
  587. package/dist/tests/multi_ne/makeStreamRpcClient.test.d.ts.map +1 -0
  588. package/dist/tests/multi_ne/makeStreamRpcClient.test.js +77 -0
  589. package/dist/tests/multi_ne/makeStreamRpcClient.test.js.map +1 -0
  590. package/dist/tests/multi_ne/media.test.d.ts +5 -0
  591. package/dist/tests/multi_ne/media.test.d.ts.map +1 -0
  592. package/dist/tests/multi_ne/media.test.js +218 -0
  593. package/dist/tests/multi_ne/media.test.js.map +1 -0
  594. package/dist/tests/multi_ne/memberMetadata.test.d.ts +5 -0
  595. package/dist/tests/multi_ne/memberMetadata.test.d.ts.map +1 -0
  596. package/dist/tests/multi_ne/memberMetadata.test.js +545 -0
  597. package/dist/tests/multi_ne/memberMetadata.test.js.map +1 -0
  598. package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.d.ts +5 -0
  599. package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.d.ts.map +1 -0
  600. package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.js +54 -0
  601. package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.js.map +1 -0
  602. package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.d.ts +5 -0
  603. package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.d.ts.map +1 -0
  604. package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.js +37 -0
  605. package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.js.map +1 -0
  606. package/dist/tests/multi_ne/memberMetadata_Nft.test.d.ts +5 -0
  607. package/dist/tests/multi_ne/memberMetadata_Nft.test.d.ts.map +1 -0
  608. package/dist/tests/multi_ne/memberMetadata_Nft.test.js +49 -0
  609. package/dist/tests/multi_ne/memberMetadata_Nft.test.js.map +1 -0
  610. package/dist/tests/multi_ne/memberMetadata_Usernames.test.d.ts +5 -0
  611. package/dist/tests/multi_ne/memberMetadata_Usernames.test.d.ts.map +1 -0
  612. package/dist/tests/multi_ne/memberMetadata_Usernames.test.js +113 -0
  613. package/dist/tests/multi_ne/memberMetadata_Usernames.test.js.map +1 -0
  614. package/dist/tests/multi_ne/nodeSelection.test.d.ts +5 -0
  615. package/dist/tests/multi_ne/nodeSelection.test.d.ts.map +1 -0
  616. package/dist/tests/multi_ne/nodeSelection.test.js +41 -0
  617. package/dist/tests/multi_ne/nodeSelection.test.js.map +1 -0
  618. package/dist/tests/multi_ne/outboundGroupSession.test.d.ts +5 -0
  619. package/dist/tests/multi_ne/outboundGroupSession.test.d.ts.map +1 -0
  620. package/dist/tests/multi_ne/outboundGroupSession.test.js +107 -0
  621. package/dist/tests/multi_ne/outboundGroupSession.test.js.map +1 -0
  622. package/dist/tests/multi_ne/persistenceStore.test.d.ts +5 -0
  623. package/dist/tests/multi_ne/persistenceStore.test.d.ts.map +1 -0
  624. package/dist/tests/multi_ne/persistenceStore.test.js +27 -0
  625. package/dist/tests/multi_ne/persistenceStore.test.js.map +1 -0
  626. package/dist/tests/multi_ne/restart.test.d.ts +4 -0
  627. package/dist/tests/multi_ne/restart.test.d.ts.map +1 -0
  628. package/dist/tests/multi_ne/restart.test.js +161 -0
  629. package/dist/tests/multi_ne/restart.test.js.map +1 -0
  630. package/dist/tests/multi_ne/sign.test.d.ts +5 -0
  631. package/dist/tests/multi_ne/sign.test.d.ts.map +1 -0
  632. package/dist/tests/multi_ne/sign.test.js +218 -0
  633. package/dist/tests/multi_ne/sign.test.js.map +1 -0
  634. package/dist/tests/multi_ne/space.test.d.ts +5 -0
  635. package/dist/tests/multi_ne/space.test.d.ts.map +1 -0
  636. package/dist/tests/multi_ne/space.test.js +190 -0
  637. package/dist/tests/multi_ne/space.test.js.map +1 -0
  638. package/dist/tests/multi_ne/streamMembershipHardening.test.d.ts +5 -0
  639. package/dist/tests/multi_ne/streamMembershipHardening.test.d.ts.map +1 -0
  640. package/dist/tests/multi_ne/streamMembershipHardening.test.js +30 -0
  641. package/dist/tests/multi_ne/streamMembershipHardening.test.js.map +1 -0
  642. package/dist/tests/multi_ne/streamRpcClient.test.d.ts +5 -0
  643. package/dist/tests/multi_ne/streamRpcClient.test.d.ts.map +1 -0
  644. package/dist/tests/multi_ne/streamRpcClient.test.js +559 -0
  645. package/dist/tests/multi_ne/streamRpcClient.test.js.map +1 -0
  646. package/dist/tests/multi_ne/streamRpcClientGetSince.test.d.ts +2 -0
  647. package/dist/tests/multi_ne/streamRpcClientGetSince.test.d.ts.map +1 -0
  648. package/dist/tests/multi_ne/streamRpcClientGetSince.test.js +105 -0
  649. package/dist/tests/multi_ne/streamRpcClientGetSince.test.js.map +1 -0
  650. package/dist/tests/multi_ne/streamRpcClientSync.test.d.ts +5 -0
  651. package/dist/tests/multi_ne/streamRpcClientSync.test.d.ts.map +1 -0
  652. package/dist/tests/multi_ne/streamRpcClientSync.test.js +199 -0
  653. package/dist/tests/multi_ne/streamRpcClientSync.test.js.map +1 -0
  654. package/dist/tests/multi_ne/streamStateView_User.test.d.ts +5 -0
  655. package/dist/tests/multi_ne/streamStateView_User.test.d.ts.map +1 -0
  656. package/dist/tests/multi_ne/streamStateView_User.test.js +31 -0
  657. package/dist/tests/multi_ne/streamStateView_User.test.js.map +1 -0
  658. package/dist/tests/multi_ne/syncWithBlocks.test.d.ts +2 -0
  659. package/dist/tests/multi_ne/syncWithBlocks.test.d.ts.map +1 -0
  660. package/dist/tests/multi_ne/syncWithBlocks.test.js +155 -0
  661. package/dist/tests/multi_ne/syncWithBlocks.test.js.map +1 -0
  662. package/dist/tests/multi_ne/syncedStream.test.d.ts +5 -0
  663. package/dist/tests/multi_ne/syncedStream.test.d.ts.map +1 -0
  664. package/dist/tests/multi_ne/syncedStream.test.js +62 -0
  665. package/dist/tests/multi_ne/syncedStream.test.js.map +1 -0
  666. package/dist/tests/multi_ne/syncedStreams.test.d.ts +5 -0
  667. package/dist/tests/multi_ne/syncedStreams.test.d.ts.map +1 -0
  668. package/dist/tests/multi_ne/syncedStreams.test.js +504 -0
  669. package/dist/tests/multi_ne/syncedStreams.test.js.map +1 -0
  670. package/dist/tests/multi_ne/tags.test.d.ts +2 -0
  671. package/dist/tests/multi_ne/tags.test.d.ts.map +1 -0
  672. package/dist/tests/multi_ne/tags.test.js +186 -0
  673. package/dist/tests/multi_ne/tags.test.js.map +1 -0
  674. package/dist/tests/multi_ne/trading.solana.test.d.ts +2 -0
  675. package/dist/tests/multi_ne/trading.solana.test.d.ts.map +1 -0
  676. package/dist/tests/multi_ne/trading.solana.test.js +229 -0
  677. package/dist/tests/multi_ne/trading.solana.test.js.map +1 -0
  678. package/dist/tests/multi_ne/trading.test.d.ts +2 -0
  679. package/dist/tests/multi_ne/trading.test.d.ts.map +1 -0
  680. package/dist/tests/multi_ne/trading.test.js +243 -0
  681. package/dist/tests/multi_ne/trading.test.js.map +1 -0
  682. package/dist/tests/multi_ne/userInboxMessage.test.d.ts +5 -0
  683. package/dist/tests/multi_ne/userInboxMessage.test.d.ts.map +1 -0
  684. package/dist/tests/multi_ne/userInboxMessage.test.js +56 -0
  685. package/dist/tests/multi_ne/userInboxMessage.test.js.map +1 -0
  686. package/dist/tests/multi_ne/userSettings.test.d.ts +5 -0
  687. package/dist/tests/multi_ne/userSettings.test.d.ts.map +1 -0
  688. package/dist/tests/multi_ne/userSettings.test.js +116 -0
  689. package/dist/tests/multi_ne/userSettings.test.js.map +1 -0
  690. package/dist/tests/multi_ne/workflows.test.d.ts +5 -0
  691. package/dist/tests/multi_ne/workflows.test.d.ts.map +1 -0
  692. package/dist/tests/multi_ne/workflows.test.js +88 -0
  693. package/dist/tests/multi_ne/workflows.test.js.map +1 -0
  694. package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.d.ts +6 -0
  695. package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.d.ts.map +1 -0
  696. package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.js +78 -0
  697. package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.js.map +1 -0
  698. package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.d.ts +6 -0
  699. package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.d.ts.map +1 -0
  700. package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.js +89 -0
  701. package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.js.map +1 -0
  702. package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.d.ts +6 -0
  703. package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.d.ts.map +1 -0
  704. package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.js +88 -0
  705. package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.js.map +1 -0
  706. package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.d.ts +6 -0
  707. package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.d.ts.map +1 -0
  708. package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.js +105 -0
  709. package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.js.map +1 -0
  710. package/dist/tests/multi_v2/updateRole.test.d.ts +5 -0
  711. package/dist/tests/multi_v2/updateRole.test.d.ts.map +1 -0
  712. package/dist/tests/multi_v2/updateRole.test.js +25 -0
  713. package/dist/tests/multi_v2/updateRole.test.js.map +1 -0
  714. package/dist/tests/syncAgent_testUtils.d.ts +10 -0
  715. package/dist/tests/syncAgent_testUtils.d.ts.map +1 -0
  716. package/dist/tests/syncAgent_testUtils.js +41 -0
  717. package/dist/tests/syncAgent_testUtils.js.map +1 -0
  718. package/dist/tests/testDriver_testUtils.d.ts +2 -0
  719. package/dist/tests/testDriver_testUtils.d.ts.map +1 -0
  720. package/dist/tests/testDriver_testUtils.js +157 -0
  721. package/dist/tests/testDriver_testUtils.js.map +1 -0
  722. package/dist/tests/testUtils.d.ts +188 -0
  723. package/dist/tests/testUtils.d.ts.map +1 -0
  724. package/dist/tests/testUtils.js +1026 -0
  725. package/dist/tests/testUtils.js.map +1 -0
  726. package/dist/tests/unit/crypto.test.d.ts +5 -0
  727. package/dist/tests/unit/crypto.test.d.ts.map +1 -0
  728. package/dist/tests/unit/crypto.test.js +109 -0
  729. package/dist/tests/unit/crypto.test.js.map +1 -0
  730. package/dist/tests/unit/crypto_utils.test.d.ts +5 -0
  731. package/dist/tests/unit/crypto_utils.test.d.ts.map +1 -0
  732. package/dist/tests/unit/crypto_utils.test.js +35 -0
  733. package/dist/tests/unit/crypto_utils.test.js.map +1 -0
  734. package/dist/tests/unit/decorators.test.d.ts +2 -0
  735. package/dist/tests/unit/decorators.test.d.ts.map +1 -0
  736. package/dist/tests/unit/decorators.test.js +76 -0
  737. package/dist/tests/unit/decorators.test.js.map +1 -0
  738. package/dist/tests/unit/snapshotMigration0000.test.d.ts +2 -0
  739. package/dist/tests/unit/snapshotMigration0000.test.d.ts.map +1 -0
  740. package/dist/tests/unit/snapshotMigration0000.test.js +12 -0
  741. package/dist/tests/unit/snapshotMigration0000.test.js.map +1 -0
  742. package/dist/tests/unit/snapshotMigration0001.test.d.ts +2 -0
  743. package/dist/tests/unit/snapshotMigration0001.test.d.ts.map +1 -0
  744. package/dist/tests/unit/snapshotMigration0001.test.js +63 -0
  745. package/dist/tests/unit/snapshotMigration0001.test.js.map +1 -0
  746. package/dist/tests/unit/snapshotMigration0002.test.d.ts +2 -0
  747. package/dist/tests/unit/snapshotMigration0002.test.d.ts.map +1 -0
  748. package/dist/tests/unit/snapshotMigration0002.test.js +31 -0
  749. package/dist/tests/unit/snapshotMigration0002.test.js.map +1 -0
  750. package/dist/tests/unit/store.test.d.ts +2 -0
  751. package/dist/tests/unit/store.test.d.ts.map +1 -0
  752. package/dist/tests/unit/store.test.js +47 -0
  753. package/dist/tests/unit/store.test.js.map +1 -0
  754. package/dist/tests/unit/testUtils.test.d.ts +5 -0
  755. package/dist/tests/unit/testUtils.test.d.ts.map +1 -0
  756. package/dist/tests/unit/testUtils.test.js +65 -0
  757. package/dist/tests/unit/testUtils.test.js.map +1 -0
  758. package/dist/types.d.ts +168 -0
  759. package/dist/types.d.ts.map +1 -0
  760. package/dist/types.js +659 -0
  761. package/dist/types.js.map +1 -0
  762. package/dist/unauthenticatedClient.d.ts +26 -0
  763. package/dist/unauthenticatedClient.d.ts.map +1 -0
  764. package/dist/unauthenticatedClient.js +156 -0
  765. package/dist/unauthenticatedClient.js.map +1 -0
  766. package/dist/utils.d.ts +28 -0
  767. package/dist/utils.d.ts.map +1 -0
  768. package/dist/utils.js +99 -0
  769. package/dist/utils.js.map +1 -0
  770. package/package.json +70 -0
package/dist/client.js ADDED
@@ -0,0 +1,1767 @@
1
+ import { create, toBinary, toJsonString } from '@bufbuild/protobuf';
2
+ import { Permission, SpaceAddressFromSpaceId, SpaceReviewAction, } from '@towns-protocol/web3';
3
+ import { MembershipOp, ChannelOp, Err, BlockchainTransactionReceipt_LogSchema, BlockchainTransactionReceiptSchema, ChannelPropertiesSchema, FullyReadMarkersSchema, ChunkedMediaSchema, EncryptedDataSchema, UserBioSchema, MemberPayload_NftSchema, ChannelMessageSchema, SolanaBlockchainTransactionReceiptSchema, SessionKeysSchema, EnvelopeSchema, } from '@towns-protocol/proto';
4
+ import { bin_fromHexString, bin_toHexString, shortenHexString, check, dlog, dlogError, bin_fromString, } from '@towns-protocol/dlog';
5
+ import { AES_GCM_DERIVED_ALGORITHM, GroupEncryptionAlgorithmId, GroupEncryptionCrypto, makeSessionKeys, } from '@towns-protocol/encryption';
6
+ import { getMaxTimeoutMs, getMiniblocks } from './makeStreamRpcClient';
7
+ import { errorContains, getRpcErrorProperty } from './rpcInterceptors';
8
+ import { assert, isDefined } from './check';
9
+ import EventEmitter from 'events';
10
+ import { isChannelStreamId, isDMChannelStreamId, isGDMChannelStreamId, isSpaceStreamId, makeDMStreamId, makeUniqueGDMChannelStreamId, makeUniqueMediaStreamId, makeUserMetadataStreamId, makeUserSettingsStreamId, makeUserStreamId, makeUserInboxStreamId, userIdFromAddress, addressFromUserId, streamIdAsBytes, streamIdAsString, makeSpaceStreamId, STREAM_ID_STRING_LENGTH, contractAddressFromSpaceId, isUserId, } from './id';
11
+ import { makeEvent, unpackStream, unpackStreamEx } from './sign';
12
+ import { StreamStateView } from './streamStateView';
13
+ import { make_UserMetadataPayload_Inception, make_ChannelPayload_Inception, make_ChannelPayload_Message, make_MemberPayload_Membership2, make_SpacePayload_Inception, make_UserPayload_Inception, make_SpacePayload_ChannelUpdate, make_UserSettingsPayload_FullyReadMarkers, make_UserSettingsPayload_UserBlock, make_UserSettingsPayload_Inception, make_MediaPayload_Inception, make_MediaPayload_Chunk, make_DMChannelPayload_Inception, make_DMChannelPayload_Message, make_GDMChannelPayload_Inception, make_GDMChannelPayload_Message, make_UserInboxPayload_Ack, make_UserInboxPayload_Inception, make_UserMetadataPayload_EncryptionDevice, make_UserInboxPayload_GroupEncryptionSessions, make_GDMChannelPayload_ChannelProperties, make_UserPayload_UserMembershipAction, make_UserPayload_UserMembership, make_MemberPayload_DisplayName, make_MemberPayload_Username, getRefEventIdFromChannelMessage, make_ChannelPayload_Redaction, make_MemberPayload_EnsAddress, make_MemberPayload_Nft, make_MemberPayload_Pin, make_MemberPayload_Unpin, make_SpacePayload_UpdateChannelAutojoin, make_SpacePayload_UpdateChannelHideUserJoinLeaveEvents, make_SpacePayload_SpaceImage, make_UserMetadataPayload_ProfileImage, make_UserMetadataPayload_Bio, make_UserPayload_BlockchainTransaction, make_MemberPayload_EncryptionAlgorithm, isSolanaTransactionReceipt, } from './types';
14
+ import debug from 'debug';
15
+ import { getTime, usernameChecksum } from './utils';
16
+ import { isEncryptedContentKind, toDecryptedContent } from './encryptedContentTypes';
17
+ import { ClientDecryptionExtensions } from './clientDecryptionExtensions';
18
+ import { PersistenceStore, StubPersistenceStore, } from './persistenceStore';
19
+ import { SyncedStreams } from './syncedStreams';
20
+ import { SyncState } from './syncedStreamsLoop';
21
+ import { SyncedStream } from './syncedStream';
22
+ import { SyncedStreamsExtension } from './syncedStreamsExtension';
23
+ import { decryptAESGCM, deriveKeyAndIV, encryptAESGCM, uint8ArrayToBase64 } from './crypto_utils';
24
+ import { makeTags, makeTipTags, makeTransferTags } from './tags';
25
+ export class Client extends EventEmitter {
26
+ opts;
27
+ signerContext;
28
+ rpcClient;
29
+ userId;
30
+ streams;
31
+ userStreamId;
32
+ userSettingsStreamId;
33
+ userMetadataStreamId;
34
+ userInboxStreamId;
35
+ logCall;
36
+ logSync;
37
+ logEmitFromStream;
38
+ logEmitFromClient;
39
+ logEvent;
40
+ logError;
41
+ logInfo;
42
+ logDebug;
43
+ cryptoBackend;
44
+ cryptoStore;
45
+ getStreamRequests = new Map();
46
+ getStreamExRequests = new Map();
47
+ initStreamRequests = new Map();
48
+ getScrollbackRequests = new Map();
49
+ creatingStreamIds = new Set();
50
+ entitlementsDelegate;
51
+ decryptionExtensions;
52
+ syncedStreamsExtensions;
53
+ persistenceStore;
54
+ defaultGroupEncryptionAlgorithm;
55
+ logId;
56
+ constructor(signerContext, rpcClient, cryptoStore, entitlementsDelegate, opts) {
57
+ super();
58
+ this.opts = opts;
59
+ if (opts?.logNamespaceFilter) {
60
+ debug.enable(opts.logNamespaceFilter);
61
+ }
62
+ assert(isDefined(signerContext.creatorAddress) && signerContext.creatorAddress.length === 20, 'creatorAddress must be set');
63
+ assert(isDefined(signerContext.signerPrivateKey()) &&
64
+ signerContext.signerPrivateKey().length === 64, 'signerPrivateKey must be set');
65
+ this.entitlementsDelegate = entitlementsDelegate;
66
+ this.signerContext = signerContext;
67
+ this.rpcClient = rpcClient;
68
+ this.userId = userIdFromAddress(signerContext.creatorAddress);
69
+ this.defaultGroupEncryptionAlgorithm =
70
+ opts?.defaultGroupEncryptionAlgorithm ??
71
+ GroupEncryptionAlgorithmId.HybridGroupEncryption;
72
+ this.logId =
73
+ opts?.logId ??
74
+ shortenHexString(this.userId.startsWith('0x') ? this.userId.slice(2) : this.userId);
75
+ this.logCall = dlog('csb:cl:call').extend(this.logId);
76
+ this.logSync = dlog('csb:cl:sync').extend(this.logId);
77
+ this.logEmitFromStream = dlog('csb:cl:stream').extend(this.logId);
78
+ this.logEmitFromClient = dlog('csb:cl:emit').extend(this.logId);
79
+ this.logEvent = dlog('csb:cl:event').extend(this.logId);
80
+ this.logError = dlogError('csb:cl:error').extend(this.logId);
81
+ this.logInfo = dlog('csb:cl:info', { defaultEnabled: true }).extend(this.logId);
82
+ this.logDebug = dlog('csb:cl:debug').extend(this.logId);
83
+ this.cryptoStore = cryptoStore;
84
+ if (opts?.persistenceStoreName) {
85
+ this.persistenceStore = new PersistenceStore(opts.persistenceStoreName);
86
+ }
87
+ else {
88
+ this.persistenceStore = new StubPersistenceStore();
89
+ }
90
+ this.streams = new SyncedStreams(this.userId, this.rpcClient, this, opts?.unpackEnvelopeOpts, this.logId, opts?.streamOpts);
91
+ this.syncedStreamsExtensions = new SyncedStreamsExtension(opts?.highPriorityStreamIds, {
92
+ startSyncStreams: async () => {
93
+ this.streams.startSyncStreams();
94
+ this.decryptionExtensions?.start();
95
+ },
96
+ initStream: (streamId, allowGetStream, persistedData) => this.initStream(streamId, allowGetStream, persistedData),
97
+ emitClientInitStatus: (status) => this.emit('clientInitStatusUpdated', status),
98
+ }, this.persistenceStore, this.logId);
99
+ this.logCall('new Client');
100
+ }
101
+ get streamSyncActive() {
102
+ return this.streams.syncState === SyncState.Syncing;
103
+ }
104
+ get clientInitStatus() {
105
+ check(this.syncedStreamsExtensions !== undefined, 'syncedStreamsExtensions must be set');
106
+ return this.syncedStreamsExtensions.initStatus;
107
+ }
108
+ get cryptoInitialized() {
109
+ return this.cryptoBackend !== undefined;
110
+ }
111
+ async stop() {
112
+ this.logCall('stop');
113
+ await this.decryptionExtensions?.stop();
114
+ await this.syncedStreamsExtensions?.stop();
115
+ await this.stopSync();
116
+ }
117
+ stream(streamId) {
118
+ return this.streams.get(streamId);
119
+ }
120
+ createSyncedStream(streamId) {
121
+ check(!this.streams.has(streamId), 'stream already exists');
122
+ const stream = new SyncedStream(this.userId, streamIdAsString(streamId), this, this.logEmitFromStream, this.persistenceStore);
123
+ this.streams.set(streamId, stream);
124
+ return stream;
125
+ }
126
+ initUserJoinedStreams() {
127
+ assert(isDefined(this.userStreamId), 'userStreamId must be set');
128
+ assert(isDefined(this.syncedStreamsExtensions), 'syncedStreamsExtensions must be set');
129
+ const stream = this.stream(this.userStreamId);
130
+ assert(isDefined(stream), 'userStream must be set');
131
+ stream.on('userJoinedStream', (s) => void this.onJoinedStream(s));
132
+ stream.on('userInvitedToStream', (s) => void this.onInvitedToStream(s));
133
+ stream.on('userLeftStream', (s) => void this.onLeftStream(s));
134
+ this.on('streamInitialized', (s) => void this.onStreamInitialized(s));
135
+ const streamIds = Object.entries(stream.view.userContent.streamMemberships).reduce((acc, [streamId, payload]) => {
136
+ if (payload.op === MembershipOp.SO_JOIN ||
137
+ (payload.op === MembershipOp.SO_INVITE &&
138
+ (isDMChannelStreamId(streamId) || isGDMChannelStreamId(streamId)))) {
139
+ acc.push(streamId);
140
+ }
141
+ return acc;
142
+ }, []);
143
+ this.syncedStreamsExtensions.setStreamIds(streamIds);
144
+ }
145
+ async initializeUser(opts) {
146
+ const initUserMetadata = opts?.spaceId
147
+ ? {
148
+ spaceId: streamIdAsBytes(opts?.spaceId),
149
+ }
150
+ : undefined;
151
+ const initializeUserStartTime = performance.now();
152
+ this.logCall('initializeUser', this.userId);
153
+ assert(this.userStreamId === undefined, 'already initialized');
154
+ const initCrypto = await getTime(() => this.initCrypto(opts?.encryptionDeviceInit));
155
+ check(isDefined(this.decryptionExtensions), 'decryptionExtensions must be defined');
156
+ check(isDefined(this.syncedStreamsExtensions), 'syncedStreamsExtensions must be defined');
157
+ const [initUserStream, initUserInboxStream, initUserMetadataStream, initUserSettingsStream,] = await Promise.all([
158
+ getTime(() => this.initUserStream(initUserMetadata)),
159
+ getTime(() => this.initUserInboxStream(initUserMetadata)),
160
+ getTime(() => this.initUserMetadataStream(initUserMetadata)),
161
+ getTime(() => this.initUserSettingsStream(initUserMetadata)),
162
+ ]);
163
+ this.initUserJoinedStreams();
164
+ this.syncedStreamsExtensions.start();
165
+ const initializeUserEndTime = performance.now();
166
+ const executionTime = initializeUserEndTime - initializeUserStartTime;
167
+ this.logCall('initializeUser::executionTime', executionTime);
168
+ // all of these init calls follow a similar pattern and call highly similar functions
169
+ // so just tracking more granular times for a single one of these as a start, so there's not too much data to digest
170
+ const initUserMetadataTimes = initUserMetadataStream.result;
171
+ return {
172
+ initCryptoTime: initCrypto.time,
173
+ initUserStreamTime: initUserStream.time,
174
+ initUserInboxStreamTime: initUserInboxStream.time,
175
+ initUserMetadataStreamTime: initUserMetadataStream.time,
176
+ initUserSettingsStreamTime: initUserSettingsStream.time,
177
+ ...initUserMetadataTimes,
178
+ };
179
+ }
180
+ onNetworkStatusChanged(isOnline) {
181
+ this.streams.onNetworkStatusChanged(isOnline);
182
+ }
183
+ async initUserStream(metadata) {
184
+ this.userStreamId = makeUserStreamId(this.userId);
185
+ const userStream = this.createSyncedStream(this.userStreamId);
186
+ if (!(await userStream.initializeFromPersistence())) {
187
+ const response = (await this.getUserStream(this.userStreamId)) ??
188
+ (await this.createUserStream(this.userStreamId, metadata));
189
+ await userStream.initializeFromResponse(response);
190
+ }
191
+ }
192
+ async initUserInboxStream(metadata) {
193
+ this.userInboxStreamId = makeUserInboxStreamId(this.userId);
194
+ const userInboxStream = this.createSyncedStream(this.userInboxStreamId);
195
+ if (!(await userInboxStream.initializeFromPersistence())) {
196
+ const response = (await this.getUserStream(this.userInboxStreamId)) ??
197
+ (await this.createUserInboxStream(this.userInboxStreamId, metadata));
198
+ await userInboxStream.initializeFromResponse(response);
199
+ }
200
+ }
201
+ async initUserMetadataStream(metadata) {
202
+ this.userMetadataStreamId = makeUserMetadataStreamId(this.userId);
203
+ const userMetadataStream = this.createSyncedStream(this.userMetadataStreamId);
204
+ let initUserMetadataStreamInitFromPersistenceTime = 0;
205
+ let initUserMetadataStreamGetUserStreamTime = 0;
206
+ let initUserMetadataStreamCreateUserMetadataStreamTime = 0;
207
+ let initUserMetadataStreamInitFromResponseTime = 0;
208
+ const initFromPersistence = await getTime(() => userMetadataStream.initializeFromPersistence());
209
+ initUserMetadataStreamInitFromPersistenceTime = initFromPersistence.time;
210
+ if (!initFromPersistence.result) {
211
+ const getUserStreamResponse = await getTime(() => {
212
+ check(!!this.userMetadataStreamId, 'userMetadataStreamId must be set');
213
+ return this.getUserStream(this.userMetadataStreamId);
214
+ });
215
+ initUserMetadataStreamGetUserStreamTime = getUserStreamResponse.time;
216
+ let response;
217
+ if (getUserStreamResponse.result) {
218
+ response = getUserStreamResponse.result;
219
+ }
220
+ else {
221
+ const createUserMetadataStreamResponse = await getTime(() => {
222
+ check(!!this.userMetadataStreamId, 'userMetadataStreamId must be set');
223
+ return this.createUserMetadataStream(this.userMetadataStreamId, metadata);
224
+ });
225
+ initUserMetadataStreamCreateUserMetadataStreamTime =
226
+ createUserMetadataStreamResponse.time;
227
+ response = createUserMetadataStreamResponse.result;
228
+ }
229
+ const initializeFromResponse = await getTime(() => userMetadataStream.initializeFromResponse(response));
230
+ initUserMetadataStreamInitFromResponseTime = initializeFromResponse.time;
231
+ }
232
+ const times = {
233
+ ...(initUserMetadataStreamInitFromPersistenceTime
234
+ ? { initUserMetadataStreamInitFromPersistenceTime }
235
+ : {}),
236
+ ...(initUserMetadataStreamGetUserStreamTime
237
+ ? { initUserMetadataStreamGetUserStreamTime }
238
+ : {}),
239
+ ...(initUserMetadataStreamCreateUserMetadataStreamTime
240
+ ? {
241
+ initUserMetadataStreamCreateUserMetadataStreamTime,
242
+ }
243
+ : {}),
244
+ ...(initUserMetadataStreamInitFromResponseTime
245
+ ? { initUserMetadataStreamInitFromResponseTime }
246
+ : {}),
247
+ };
248
+ return times;
249
+ }
250
+ async initUserSettingsStream(metadata) {
251
+ this.userSettingsStreamId = makeUserSettingsStreamId(this.userId);
252
+ const userSettingsStream = this.createSyncedStream(this.userSettingsStreamId);
253
+ if (!(await userSettingsStream.initializeFromPersistence())) {
254
+ const response = (await this.getUserStream(this.userSettingsStreamId)) ??
255
+ (await this.createUserSettingsStream(this.userSettingsStreamId, metadata));
256
+ await userSettingsStream.initializeFromResponse(response);
257
+ }
258
+ }
259
+ async getUserStream(streamId) {
260
+ const response = await this.rpcClient.getStream({
261
+ streamId: streamIdAsBytes(streamId),
262
+ optional: true,
263
+ });
264
+ if (response.stream) {
265
+ return unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
266
+ }
267
+ else {
268
+ return undefined;
269
+ }
270
+ }
271
+ async createUserStream(userStreamId, metadata) {
272
+ const userEvents = [
273
+ await makeEvent(this.signerContext, make_UserPayload_Inception({
274
+ streamId: streamIdAsBytes(userStreamId),
275
+ })),
276
+ ];
277
+ const response = await this.rpcClient.createStream({
278
+ events: userEvents,
279
+ streamId: streamIdAsBytes(userStreamId),
280
+ metadata: metadata,
281
+ });
282
+ return unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
283
+ }
284
+ async createUserMetadataStream(userMetadataStreamId, metadata) {
285
+ const userDeviceKeyEvents = [
286
+ await makeEvent(this.signerContext, make_UserMetadataPayload_Inception({
287
+ streamId: streamIdAsBytes(userMetadataStreamId),
288
+ })),
289
+ ];
290
+ const response = await this.rpcClient.createStream({
291
+ events: userDeviceKeyEvents,
292
+ streamId: streamIdAsBytes(userMetadataStreamId),
293
+ metadata: metadata,
294
+ });
295
+ return unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
296
+ }
297
+ async createUserInboxStream(userInboxStreamId, metadata) {
298
+ const userInboxEvents = [
299
+ await makeEvent(this.signerContext, make_UserInboxPayload_Inception({
300
+ streamId: streamIdAsBytes(userInboxStreamId),
301
+ })),
302
+ ];
303
+ const response = await this.rpcClient.createStream({
304
+ events: userInboxEvents,
305
+ streamId: streamIdAsBytes(userInboxStreamId),
306
+ metadata: metadata,
307
+ });
308
+ return unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
309
+ }
310
+ async createUserSettingsStream(inUserSettingsStreamId, metadata) {
311
+ const userSettingsStreamId = streamIdAsBytes(inUserSettingsStreamId);
312
+ const userSettingsEvents = [
313
+ await makeEvent(this.signerContext, make_UserSettingsPayload_Inception({
314
+ streamId: userSettingsStreamId,
315
+ })),
316
+ ];
317
+ const response = await this.rpcClient.createStream({
318
+ events: userSettingsEvents,
319
+ streamId: userSettingsStreamId,
320
+ metadata: metadata,
321
+ });
322
+ return unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
323
+ }
324
+ async createStreamAndSync(request) {
325
+ const streamId = streamIdAsString(request.streamId);
326
+ try {
327
+ this.creatingStreamIds.add(streamId);
328
+ let response = await this.rpcClient.createStream(request);
329
+ const stream = this.createSyncedStream(streamId);
330
+ if (!response.stream) {
331
+ // if a stream alread exists it will return a nil stream in the response, but no error
332
+ // fetch the stream to get the client in the rigth state
333
+ response = await this.rpcClient.getStream({ streamId: request.streamId });
334
+ }
335
+ const unpacked = await unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
336
+ await stream.initializeFromResponse(unpacked);
337
+ if (stream.view.syncCookie) {
338
+ this.streams.addStreamToSync(streamId, stream.view.syncCookie);
339
+ }
340
+ }
341
+ catch (err) {
342
+ this.logError('Failed to create stream', streamId);
343
+ this.streams.delete(streamId);
344
+ this.creatingStreamIds.delete(streamId);
345
+ throw err;
346
+ }
347
+ return { streamId: streamId };
348
+ }
349
+ // createSpace
350
+ // param spaceAddress: address of the space contract, or address made with makeSpaceStreamId
351
+ async createSpace(spaceAddressOrId) {
352
+ const oSpaceId = spaceAddressOrId.length === STREAM_ID_STRING_LENGTH
353
+ ? spaceAddressOrId
354
+ : makeSpaceStreamId(spaceAddressOrId);
355
+ const spaceId = streamIdAsBytes(oSpaceId);
356
+ this.logCall('createSpace', spaceId);
357
+ assert(this.userStreamId !== undefined, 'streamId must be set');
358
+ assert(isSpaceStreamId(spaceId), 'spaceId must be a valid streamId');
359
+ // create utf8 encoder
360
+ const inceptionEvent = await makeEvent(this.signerContext, make_SpacePayload_Inception({
361
+ streamId: spaceId,
362
+ }));
363
+ const joinEvent = await makeEvent(this.signerContext, make_MemberPayload_Membership2({
364
+ userId: this.userId,
365
+ op: MembershipOp.SO_JOIN,
366
+ initiatorId: this.userId,
367
+ }));
368
+ return this.createStreamAndSync({
369
+ events: [inceptionEvent, joinEvent],
370
+ streamId: spaceId,
371
+ metadata: {},
372
+ });
373
+ }
374
+ async createChannel(spaceId, channelName, channelTopic, inChannelId, streamSettings, channelSettings) {
375
+ const oChannelId = inChannelId;
376
+ const channelId = streamIdAsBytes(oChannelId);
377
+ this.logCall('createChannel', channelId, spaceId);
378
+ assert(this.userStreamId !== undefined, 'userStreamId must be set');
379
+ assert(isSpaceStreamId(spaceId), 'spaceId must be a valid streamId');
380
+ assert(isChannelStreamId(channelId), 'channelId must be a valid streamId');
381
+ const inceptionEvent = await makeEvent(this.signerContext, make_ChannelPayload_Inception({
382
+ streamId: channelId,
383
+ spaceId: streamIdAsBytes(spaceId),
384
+ settings: streamSettings,
385
+ channelSettings: channelSettings,
386
+ }));
387
+ const joinEvent = await makeEvent(this.signerContext, make_MemberPayload_Membership2({
388
+ userId: this.userId,
389
+ op: MembershipOp.SO_JOIN,
390
+ initiatorId: this.userId,
391
+ }));
392
+ return this.createStreamAndSync({
393
+ events: [inceptionEvent, joinEvent],
394
+ streamId: channelId,
395
+ metadata: {},
396
+ });
397
+ }
398
+ async createDMChannel(userId, streamSettings) {
399
+ const channelIdStr = makeDMStreamId(this.userId, userId);
400
+ const channelId = streamIdAsBytes(channelIdStr);
401
+ const inceptionEvent = await makeEvent(this.signerContext, make_DMChannelPayload_Inception({
402
+ streamId: channelId,
403
+ firstPartyAddress: this.signerContext.creatorAddress,
404
+ secondPartyAddress: addressFromUserId(userId),
405
+ settings: streamSettings,
406
+ }));
407
+ const joinEvent = await makeEvent(this.signerContext, make_MemberPayload_Membership2({
408
+ userId: this.userId,
409
+ op: MembershipOp.SO_JOIN,
410
+ initiatorId: this.userId,
411
+ }));
412
+ const inviteEvent = await makeEvent(this.signerContext, make_MemberPayload_Membership2({
413
+ userId: userId,
414
+ op: MembershipOp.SO_JOIN,
415
+ initiatorId: this.userId,
416
+ }));
417
+ return this.createStreamAndSync({
418
+ events: [inceptionEvent, joinEvent, inviteEvent],
419
+ streamId: channelId,
420
+ metadata: {},
421
+ });
422
+ }
423
+ async createGDMChannel(userIds, channelProperties, streamSettings) {
424
+ const channelIdStr = makeUniqueGDMChannelStreamId();
425
+ const channelId = streamIdAsBytes(channelIdStr);
426
+ const events = [];
427
+ const inceptionEvent = await makeEvent(this.signerContext, make_GDMChannelPayload_Inception({
428
+ streamId: channelId,
429
+ channelProperties: channelProperties,
430
+ settings: streamSettings,
431
+ }));
432
+ events.push(inceptionEvent);
433
+ const joinEvent = await makeEvent(this.signerContext, make_MemberPayload_Membership2({
434
+ userId: this.userId,
435
+ op: MembershipOp.SO_JOIN,
436
+ initiatorId: this.userId,
437
+ }));
438
+ events.push(joinEvent);
439
+ for (const userId of userIds) {
440
+ const inviteEvent = await makeEvent(this.signerContext, make_MemberPayload_Membership2({
441
+ userId: userId,
442
+ op: MembershipOp.SO_JOIN,
443
+ initiatorId: this.userId,
444
+ }));
445
+ events.push(inviteEvent);
446
+ }
447
+ return this.createStreamAndSync({
448
+ events: events,
449
+ streamId: channelId,
450
+ metadata: {},
451
+ });
452
+ }
453
+ async createMediaStream(channelId, spaceId, userId, chunkCount, firstChunk, firstChunkIv, streamSettings, perChunkEncryption) {
454
+ assert(this.userStreamId !== undefined, 'userStreamId must be set');
455
+ if (!channelId && !spaceId && !userId) {
456
+ throw Error('channelId, spaceId or userId must be set');
457
+ }
458
+ if (spaceId) {
459
+ assert(isSpaceStreamId(spaceId), 'spaceId must be a valid streamId');
460
+ }
461
+ if (channelId) {
462
+ assert(isChannelStreamId(channelId) ||
463
+ isDMChannelStreamId(channelId) ||
464
+ isGDMChannelStreamId(channelId), 'channelId must be a valid streamId');
465
+ }
466
+ if (userId) {
467
+ assert(isUserId(userId), 'userId must be a valid userId');
468
+ }
469
+ const streamId = makeUniqueMediaStreamId();
470
+ const events = [];
471
+ this.logCall('createMedia', channelId ?? spaceId, userId, streamId);
472
+ // Prepare inception event
473
+ events.push(await makeEvent(this.signerContext, make_MediaPayload_Inception({
474
+ streamId: streamIdAsBytes(streamId),
475
+ channelId: channelId ? streamIdAsBytes(channelId) : undefined,
476
+ spaceId: spaceId ? streamIdAsBytes(spaceId) : undefined,
477
+ userId: userId ? addressFromUserId(userId) : undefined,
478
+ chunkCount,
479
+ settings: streamSettings,
480
+ perChunkEncryption: perChunkEncryption,
481
+ })));
482
+ // Prepare first chunk event
483
+ if (firstChunk && firstChunk.length > 0) {
484
+ events.push(await makeEvent(this.signerContext, make_MediaPayload_Chunk({
485
+ data: firstChunk,
486
+ chunkIndex: 0,
487
+ iv: firstChunkIv,
488
+ })));
489
+ }
490
+ const response = await this.rpcClient.createMediaStream({
491
+ events: events,
492
+ streamId: streamIdAsBytes(streamId),
493
+ });
494
+ check(response?.nextCreationCookie !== undefined, 'nextCreationCookie was expected but was not returned in response');
495
+ return { creationCookie: response.nextCreationCookie };
496
+ }
497
+ async updateChannel(spaceId, channelId, unused1, unused2) {
498
+ this.logCall('updateChannel', channelId, spaceId, unused1, unused2);
499
+ assert(isSpaceStreamId(spaceId), 'spaceId must be a valid streamId');
500
+ assert(isChannelStreamId(channelId), 'channelId must be a valid streamId');
501
+ return this.makeEventAndAddToStream(spaceId, // we send events to the stream of the space where updated channel belongs to
502
+ make_SpacePayload_ChannelUpdate({
503
+ op: ChannelOp.CO_UPDATED,
504
+ channelId: streamIdAsBytes(channelId),
505
+ }), { method: 'updateChannel' });
506
+ }
507
+ async updateChannelAutojoin(spaceId, channelId, autojoin) {
508
+ this.logCall('updateChannelAutojoin', channelId, spaceId, autojoin);
509
+ assert(isSpaceStreamId(spaceId), 'spaceId must be a valid streamId');
510
+ assert(isChannelStreamId(channelId), 'channelId must be a valid streamId');
511
+ return this.makeEventAndAddToStream(spaceId, // we send events to the stream of the space where updated channel belongs to
512
+ make_SpacePayload_UpdateChannelAutojoin({
513
+ channelId: streamIdAsBytes(channelId),
514
+ autojoin: autojoin,
515
+ }), { method: 'updateChannelAutojoin' });
516
+ }
517
+ async updateChannelHideUserJoinLeaveEvents(spaceId, channelId, hideUserJoinLeaveEvents) {
518
+ this.logCall('updateChannelHideUserJoinLeaveEvents', channelId, spaceId, hideUserJoinLeaveEvents);
519
+ assert(isSpaceStreamId(spaceId), 'spaceId must be a valid streamId');
520
+ assert(isChannelStreamId(channelId), 'channelId must be a valid streamId');
521
+ return this.makeEventAndAddToStream(spaceId, // we send events to the stream of the space where updated channel belongs to
522
+ make_SpacePayload_UpdateChannelHideUserJoinLeaveEvents({
523
+ channelId: streamIdAsBytes(channelId),
524
+ hideUserJoinLeaveEvents,
525
+ }), { method: 'updateChannelHideUserJoinLeaveEvents' });
526
+ }
527
+ async updateGDMChannelProperties(streamId, channelName, channelTopic) {
528
+ this.logCall('updateGDMChannelProperties', streamId, channelName, channelTopic);
529
+ assert(isGDMChannelStreamId(streamId), 'streamId must be a valid GDM stream id');
530
+ check(isDefined(this.cryptoBackend));
531
+ const channelProps = create(ChannelPropertiesSchema, {
532
+ name: channelName,
533
+ topic: channelTopic,
534
+ });
535
+ const encryptedData = await this.cryptoBackend.encryptGroupEvent(streamId, toBinary(ChannelPropertiesSchema, channelProps), this.defaultGroupEncryptionAlgorithm);
536
+ const event = make_GDMChannelPayload_ChannelProperties(encryptedData);
537
+ return this.makeEventAndAddToStream(streamId, event, {
538
+ method: 'updateGDMChannelProperties',
539
+ });
540
+ }
541
+ async setStreamEncryptionAlgorithm(streamId, encryptionAlgorithm) {
542
+ assert(isChannelStreamId(streamId) ||
543
+ isSpaceStreamId(streamId) ||
544
+ isDMChannelStreamId(streamId) ||
545
+ isGDMChannelStreamId(streamId), 'channelId must be a valid streamId');
546
+ const stream = this.stream(streamId);
547
+ check(isDefined(stream), 'stream not found');
548
+ check(stream.view.membershipContent.encryptionAlgorithm != encryptionAlgorithm, `encryptionAlgorithm is already set to ${encryptionAlgorithm}`);
549
+ return this.makeEventAndAddToStream(streamId, make_MemberPayload_EncryptionAlgorithm(encryptionAlgorithm), {
550
+ method: 'setStreamEncryptionAlgorithm',
551
+ });
552
+ }
553
+ async sendFullyReadMarkers(channelId, fullyReadMarkers) {
554
+ this.logCall('sendFullyReadMarker', fullyReadMarkers);
555
+ if (!isDefined(this.userSettingsStreamId)) {
556
+ throw Error('userSettingsStreamId is not defined');
557
+ }
558
+ const fullyReadMarkersContent = create(FullyReadMarkersSchema, {
559
+ markers: fullyReadMarkers,
560
+ });
561
+ return this.makeEventAndAddToStream(this.userSettingsStreamId, make_UserSettingsPayload_FullyReadMarkers({
562
+ streamId: streamIdAsBytes(channelId),
563
+ content: { data: toJsonString(FullyReadMarkersSchema, fullyReadMarkersContent) },
564
+ }), { method: 'sendFullyReadMarker' });
565
+ }
566
+ async updateUserBlock(userId, isBlocked) {
567
+ this.logCall('blockUser', userId);
568
+ if (!isDefined(this.userSettingsStreamId)) {
569
+ throw Error('userSettingsStreamId is not defined');
570
+ }
571
+ const dmStreamId = makeDMStreamId(this.userId, userId);
572
+ const lastBlock = this.stream(this.userSettingsStreamId)?.view.userSettingsContent.getLastBlock(userId);
573
+ if (lastBlock?.isBlocked === isBlocked) {
574
+ throw Error(`updateUserBlock isBlocked<${isBlocked}> must be different from existing value`);
575
+ }
576
+ let eventNum = this.stream(dmStreamId)?.view.lastEventNum ?? 0n;
577
+ if (lastBlock && lastBlock.eventNum >= eventNum) {
578
+ eventNum = lastBlock.eventNum + 1n;
579
+ }
580
+ return this.makeEventAndAddToStream(this.userSettingsStreamId, make_UserSettingsPayload_UserBlock({
581
+ userId: addressFromUserId(userId),
582
+ isBlocked: isBlocked,
583
+ eventNum: eventNum,
584
+ }), { method: 'updateUserBlock' });
585
+ }
586
+ async setSpaceImage(spaceStreamId, chunkedMediaInfo) {
587
+ this.logCall('setSpaceImage', spaceStreamId, chunkedMediaInfo.streamId, chunkedMediaInfo.info);
588
+ // create the chunked media to be added
589
+ const spaceAddress = contractAddressFromSpaceId(spaceStreamId);
590
+ const context = spaceAddress.toLowerCase();
591
+ // encrypt the chunked media
592
+ // use the lowercased spaceId as the key phrase
593
+ const { key, iv } = await deriveKeyAndIV(context);
594
+ const { ciphertext } = await encryptAESGCM(toBinary(ChunkedMediaSchema, create(ChunkedMediaSchema, chunkedMediaInfo)), key, iv);
595
+ const encryptedData = create(EncryptedDataSchema, {
596
+ ciphertext: uint8ArrayToBase64(ciphertext),
597
+ algorithm: AES_GCM_DERIVED_ALGORITHM,
598
+ }); // aellis this should probably include `satisfies PlainMessage<EncryptedData>`
599
+ // add the event to the stream
600
+ const event = make_SpacePayload_SpaceImage(encryptedData);
601
+ return this.makeEventAndAddToStream(spaceStreamId, event, { method: 'setSpaceImage' });
602
+ }
603
+ async setUserProfileImage(chunkedMediaInfo) {
604
+ this.logCall('setUserProfileImage', chunkedMediaInfo.streamId, chunkedMediaInfo.info);
605
+ // create the chunked media to be added
606
+ const context = this.userId.toLowerCase();
607
+ const userStreamId = makeUserMetadataStreamId(this.userId);
608
+ // encrypt the chunked media
609
+ // use the lowercased userId as the key phrase
610
+ const { key, iv } = await deriveKeyAndIV(context);
611
+ const { ciphertext } = await encryptAESGCM(toBinary(ChunkedMediaSchema, create(ChunkedMediaSchema, chunkedMediaInfo)), key, iv);
612
+ const encryptedData = create(EncryptedDataSchema, {
613
+ ciphertext: uint8ArrayToBase64(ciphertext),
614
+ algorithm: AES_GCM_DERIVED_ALGORITHM,
615
+ }); // aellis this should probably include `satisfies PlainMessage<EncryptedData>`
616
+ // add the event to the stream
617
+ const event = make_UserMetadataPayload_ProfileImage(encryptedData);
618
+ return this.makeEventAndAddToStream(userStreamId, event, { method: 'setUserProfileImage' });
619
+ }
620
+ async getUserProfileImage(userId) {
621
+ const streamId = makeUserMetadataStreamId(userId);
622
+ return this.stream(streamId)?.view.userMetadataContent.getProfileImage();
623
+ }
624
+ async setUserBio(bio) {
625
+ this.logCall('setUserBio', bio);
626
+ // create the chunked media to be added
627
+ const context = this.userId.toLowerCase();
628
+ const userStreamId = makeUserMetadataStreamId(this.userId);
629
+ // encrypt the chunked media
630
+ // use the lowercased userId as the key phrase
631
+ const { key, iv } = await deriveKeyAndIV(context);
632
+ bio.updatedAtEpochMs = BigInt(Date.now());
633
+ const bioBinary = toBinary(UserBioSchema, create(UserBioSchema, bio));
634
+ const { ciphertext } = await encryptAESGCM(bioBinary, key, iv);
635
+ const encryptedData = create(EncryptedDataSchema, {
636
+ ciphertext: uint8ArrayToBase64(ciphertext),
637
+ algorithm: AES_GCM_DERIVED_ALGORITHM,
638
+ }); // aellis this should probably include `satisfies PlainMessage<EncryptedData>`
639
+ // add the event to the stream
640
+ const event = make_UserMetadataPayload_Bio(encryptedData);
641
+ return this.makeEventAndAddToStream(userStreamId, event, { method: 'setUserBio' });
642
+ }
643
+ async getUserBio(userId) {
644
+ const streamId = makeUserMetadataStreamId(userId);
645
+ return this.stream(streamId)?.view.userMetadataContent.getBio();
646
+ }
647
+ async setDisplayName(streamId, displayName) {
648
+ check(isDefined(this.cryptoBackend));
649
+ const encryptedData = await this.cryptoBackend.encryptGroupEvent(streamId, new TextEncoder().encode(displayName), this.defaultGroupEncryptionAlgorithm);
650
+ await this.makeEventAndAddToStream(streamId, make_MemberPayload_DisplayName(encryptedData), { method: 'displayName' });
651
+ }
652
+ async setUsername(streamId, username) {
653
+ check(isDefined(this.cryptoBackend));
654
+ const stream = this.stream(streamId);
655
+ check(isDefined(stream), 'stream not found');
656
+ stream.view.getMemberMetadata().usernames.setLocalUsername(this.userId, username);
657
+ const encryptedData = await this.cryptoBackend.encryptGroupEvent(streamId, new TextEncoder().encode(username), this.defaultGroupEncryptionAlgorithm);
658
+ encryptedData.checksum = usernameChecksum(username, streamId);
659
+ try {
660
+ await this.makeEventAndAddToStream(streamId, make_MemberPayload_Username(encryptedData), {
661
+ method: 'username',
662
+ });
663
+ }
664
+ catch (err) {
665
+ stream.view.getMemberMetadata().usernames.resetLocalUsername(this.userId);
666
+ throw err;
667
+ }
668
+ }
669
+ async setEnsAddress(streamId, walletAddress) {
670
+ check(isDefined(this.cryptoBackend));
671
+ const bytes = typeof walletAddress === 'string' ? addressFromUserId(walletAddress) : walletAddress;
672
+ await this.makeEventAndAddToStream(streamId, make_MemberPayload_EnsAddress(bytes), {
673
+ method: 'ensAddress',
674
+ });
675
+ }
676
+ async setNft(streamId, tokenId, chainId, contractAddress) {
677
+ const payload = tokenId.length > 0
678
+ ? create(MemberPayload_NftSchema, {
679
+ chainId: chainId,
680
+ contractAddress: bin_fromHexString(contractAddress),
681
+ tokenId: bin_fromString(tokenId),
682
+ })
683
+ : create(MemberPayload_NftSchema);
684
+ await this.makeEventAndAddToStream(streamId, make_MemberPayload_Nft(payload), {
685
+ method: 'nft',
686
+ });
687
+ }
688
+ async pin(streamId, eventId) {
689
+ const stream = this.streams.get(streamId);
690
+ check(isDefined(stream), 'stream not found');
691
+ const event = stream.view.events.get(eventId);
692
+ check(isDefined(event), 'event not found');
693
+ const remoteEvent = event.remoteEvent;
694
+ check(isDefined(remoteEvent), 'remoteEvent not found');
695
+ const result = await this.makeEventAndAddToStream(streamId, make_MemberPayload_Pin(remoteEvent.hash, remoteEvent.event), {
696
+ method: 'pin',
697
+ });
698
+ return result;
699
+ }
700
+ async unpin(streamId, eventId) {
701
+ const stream = this.streams.get(streamId);
702
+ check(isDefined(stream), 'stream not found');
703
+ const pin = stream.view.membershipContent.pins.find((x) => x.event.hashStr === eventId);
704
+ check(isDefined(pin), 'pin not found');
705
+ check(isDefined(pin.event.remoteEvent), 'remoteEvent not found');
706
+ const result = await this.makeEventAndAddToStream(streamId, make_MemberPayload_Unpin(pin.event.remoteEvent.hash), {
707
+ method: 'unpin',
708
+ });
709
+ return result;
710
+ }
711
+ isUsernameAvailable(streamId, username) {
712
+ const stream = this.streams.get(streamId);
713
+ check(isDefined(stream), 'stream not found');
714
+ return (stream.view.getMemberMetadata().usernames.cleartextUsernameAvailable(username) ?? false);
715
+ }
716
+ async waitForStream(inStreamId, opts) {
717
+ this.logCall('waitForStream', inStreamId);
718
+ const timeoutMs = opts?.timeoutMs ?? getMaxTimeoutMs(this.rpcClient.opts);
719
+ const streamId = streamIdAsString(inStreamId);
720
+ let stream = this.stream(streamId);
721
+ if (stream !== undefined && stream.view.isInitialized) {
722
+ this.logCall('waitForStream: stream already initialized', streamId);
723
+ return stream;
724
+ }
725
+ const logId = opts?.logId ? opts.logId + ' ' : '';
726
+ const timeoutError = new Error(`waitForStream: timeout waiting for ${logId}${streamId} creating streams: ${Array.from(this.creatingStreamIds).join(',')} rpcUrl: ${this.rpcClient.url}`);
727
+ await new Promise((resolve, reject) => {
728
+ const timeout = setTimeout(() => {
729
+ this.off('streamInitialized', handler);
730
+ reject(timeoutError);
731
+ }, timeoutMs);
732
+ const handler = (newStreamId) => {
733
+ if (newStreamId === streamId) {
734
+ this.logCall('waitForStream: got streamInitialized', newStreamId);
735
+ this.off('streamInitialized', handler);
736
+ clearTimeout(timeout);
737
+ resolve();
738
+ }
739
+ else {
740
+ this.logCall('waitForStream: still waiting for ', streamId, ' got ', newStreamId);
741
+ }
742
+ };
743
+ this.on('streamInitialized', handler);
744
+ });
745
+ stream = this.stream(streamId);
746
+ if (!stream) {
747
+ throw new Error(`Stream ${streamIdAsString(streamId)} not found after waiting`);
748
+ }
749
+ return stream;
750
+ }
751
+ async getStream(streamId) {
752
+ const existingRequest = this.getStreamRequests.get(streamId);
753
+ if (existingRequest) {
754
+ this.logCall(`had existing get request for ${streamId}, returning promise`);
755
+ return await existingRequest;
756
+ }
757
+ const request = this._getStream(streamId);
758
+ this.getStreamRequests.set(streamId, request);
759
+ let streamView;
760
+ try {
761
+ streamView = await request;
762
+ }
763
+ finally {
764
+ this.getStreamRequests.delete(streamId);
765
+ }
766
+ return streamView;
767
+ }
768
+ async _getStream(streamId) {
769
+ try {
770
+ this.logCall('getStream', streamId);
771
+ const response = await this.rpcClient.getStream({
772
+ streamId: streamIdAsBytes(streamId),
773
+ });
774
+ const unpackedResponse = await unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
775
+ return this.streamViewFromUnpackedResponse(streamId, unpackedResponse);
776
+ }
777
+ catch (err) {
778
+ this.logCall('getStream', streamId, 'ERROR', err);
779
+ throw err;
780
+ }
781
+ }
782
+ streamViewFromUnpackedResponse(streamId, unpackedResponse) {
783
+ const streamView = new StreamStateView(this.userId, streamIdAsString(streamId));
784
+ streamView.initialize(unpackedResponse.streamAndCookie.nextSyncCookie, unpackedResponse.streamAndCookie.events, unpackedResponse.snapshot, unpackedResponse.streamAndCookie.miniblocks, [], unpackedResponse.prevSnapshotMiniblockNum, undefined, [], undefined);
785
+ return streamView;
786
+ }
787
+ async getStreamEx(streamId) {
788
+ const existingRequest = this.getStreamExRequests.get(streamId);
789
+ if (existingRequest) {
790
+ this.logCall(`had existing get request for ${streamId}, returning promise`);
791
+ return await existingRequest;
792
+ }
793
+ const request = this._getStreamEx(streamId);
794
+ this.getStreamExRequests.set(streamId, request);
795
+ let streamView;
796
+ try {
797
+ streamView = await request;
798
+ }
799
+ finally {
800
+ this.getStreamExRequests.delete(streamId);
801
+ }
802
+ return streamView;
803
+ }
804
+ async _getStreamEx(streamId) {
805
+ try {
806
+ this.logCall('getStreamEx', streamId);
807
+ const response = this.rpcClient.getStreamEx({
808
+ streamId: streamIdAsBytes(streamId),
809
+ });
810
+ const miniblocks = [];
811
+ let seenEndOfStream = false;
812
+ for await (const chunk of response) {
813
+ switch (chunk.data.case) {
814
+ case 'miniblock':
815
+ if (seenEndOfStream) {
816
+ throw new Error(`GetStreamEx: received miniblock after minipool contents for stream ${streamIdAsString(streamId)}.`);
817
+ }
818
+ miniblocks.push(chunk.data.value);
819
+ break;
820
+ case 'minipool':
821
+ // TODO: add minipool contents to the unpacked response
822
+ break;
823
+ case undefined:
824
+ seenEndOfStream = true;
825
+ break;
826
+ }
827
+ }
828
+ if (!seenEndOfStream) {
829
+ throw new Error(`Failed receive all getStreamEx streaming responses for stream ${streamIdAsString(streamId)}.`);
830
+ }
831
+ const unpackedResponse = await unpackStreamEx(miniblocks, this.opts?.unpackEnvelopeOpts);
832
+ return this.streamViewFromUnpackedResponse(streamId, unpackedResponse);
833
+ }
834
+ catch (err) {
835
+ this.logCall('getStreamEx', streamId, 'ERROR', err);
836
+ throw err;
837
+ }
838
+ }
839
+ async initStream(streamId, allowGetStream = true, persistedData) {
840
+ const streamIdStr = streamIdAsString(streamId);
841
+ const existingRequest = this.initStreamRequests.get(streamIdStr);
842
+ if (existingRequest) {
843
+ this.logCall('initStream: had existing request for', streamIdStr, 'returning promise');
844
+ return existingRequest;
845
+ }
846
+ const request = this._initStream(streamIdStr, allowGetStream, persistedData);
847
+ this.initStreamRequests.set(streamIdStr, request);
848
+ let stream;
849
+ try {
850
+ stream = await request;
851
+ }
852
+ finally {
853
+ this.initStreamRequests.delete(streamIdStr);
854
+ }
855
+ return stream;
856
+ }
857
+ async _initStream(streamId, allowGetStream = true, persistedData) {
858
+ try {
859
+ this.logCall('initStream', streamId);
860
+ const stream = this.stream(streamId);
861
+ if (stream) {
862
+ if (stream.view.isInitialized) {
863
+ this.logCall('initStream', streamId, 'already initialized');
864
+ return stream;
865
+ }
866
+ else {
867
+ return this.waitForStream(streamId);
868
+ }
869
+ }
870
+ else {
871
+ this.logCall('initStream creating stream', streamId);
872
+ const stream = this.createSyncedStream(streamId);
873
+ // Try initializing from persistence
874
+ const success = await stream.initializeFromPersistence(persistedData);
875
+ if (success) {
876
+ if (stream.view.syncCookie) {
877
+ this.streams.addStreamToSync(streamId, stream.view.syncCookie);
878
+ }
879
+ return stream;
880
+ }
881
+ // if we're only allowing initializing from persistence, we've failed.
882
+ if (!allowGetStream) {
883
+ this.logCall('initStream deleting stream', streamId);
884
+ // We need to remove the stream from syncedStreams, since we added it above
885
+ this.streams.delete(streamId);
886
+ throw new Error(`Failed to initialize stream from persistence ${streamIdAsString(streamId)}`);
887
+ }
888
+ try {
889
+ const response = await this.rpcClient.getStream({
890
+ streamId: streamIdAsBytes(streamId),
891
+ });
892
+ const unpacked = await unpackStream(response.stream, this.opts?.unpackEnvelopeOpts);
893
+ this.logCall('initStream calling initializingFromResponse', streamId);
894
+ await stream.initializeFromResponse(unpacked);
895
+ if (stream.view.syncCookie) {
896
+ this.streams.addStreamToSync(streamId, stream.view.syncCookie);
897
+ }
898
+ }
899
+ catch (err) {
900
+ this.logError('Failed to initialize stream', streamId, err);
901
+ this.streams.delete(streamId);
902
+ throw err;
903
+ }
904
+ return stream;
905
+ }
906
+ }
907
+ catch (err) {
908
+ this.logCall('initStream', streamId, 'ERROR', err);
909
+ throw err;
910
+ }
911
+ }
912
+ onJoinedStream = async (streamId) => {
913
+ this.logEvent('onJoinedStream', streamId);
914
+ if (!this.creatingStreamIds.has(streamId)) {
915
+ await this.initStream(streamId);
916
+ }
917
+ };
918
+ onInvitedToStream = async (streamId) => {
919
+ this.logEvent('onInvitedToStream', streamId);
920
+ if (isDMChannelStreamId(streamId) || isGDMChannelStreamId(streamId)) {
921
+ await this.initStream(streamId);
922
+ }
923
+ };
924
+ onLeftStream = async (streamId) => {
925
+ this.logEvent('onLeftStream', streamId);
926
+ return await this.streams.removeStreamFromSync(streamId);
927
+ };
928
+ onStreamInitialized = (streamId) => {
929
+ const scrollbackUntilContentFound = async () => {
930
+ const stream = this.streams.get(streamId);
931
+ if (!stream) {
932
+ return;
933
+ }
934
+ while (stream.view.getContent().needsScrollback()) {
935
+ const scrollback = await this.scrollback(streamId);
936
+ if (scrollback.terminus) {
937
+ break;
938
+ }
939
+ }
940
+ };
941
+ void scrollbackUntilContentFound();
942
+ };
943
+ startSync() {
944
+ check(this.syncedStreamsExtensions !== undefined, 'syncedStreamsExtensions must be set');
945
+ this.syncedStreamsExtensions.setStartSyncRequested(true);
946
+ }
947
+ async stopSync() {
948
+ this.syncedStreamsExtensions?.setStartSyncRequested(false);
949
+ await this.streams.stopSync();
950
+ }
951
+ emit(event, ...args) {
952
+ this.logEmitFromClient(event, ...args);
953
+ return super.emit(event, ...args);
954
+ }
955
+ async sendMessage(streamId, body, mentions, attachments = []) {
956
+ return this.sendChannelMessage_Text(streamId, {
957
+ content: {
958
+ body,
959
+ mentions: mentions ?? [],
960
+ attachments: attachments,
961
+ },
962
+ });
963
+ }
964
+ async sendChannelMessage(streamId, inPayload, opts) {
965
+ const stream = this.stream(streamId);
966
+ check(stream !== undefined, 'stream not found');
967
+ const payload = create(ChannelMessageSchema, inPayload);
968
+ const localId = stream.appendLocalEvent(payload, 'sending');
969
+ opts?.onLocalEventAppended?.(localId);
970
+ if (opts?.beforeSendEventHook) {
971
+ await opts?.beforeSendEventHook;
972
+ }
973
+ return this.makeAndSendChannelMessageEvent(streamId, payload, localId, {
974
+ disableTags: opts?.disableTags,
975
+ });
976
+ }
977
+ async makeAndSendChannelMessageEvent(streamId, payload, localId, opts) {
978
+ const stream = this.stream(streamId);
979
+ check(isDefined(stream), 'stream not found');
980
+ if (isChannelStreamId(streamId)) {
981
+ // All channel messages sent via client API make their way to this method.
982
+ // The client checks for it's own entitlement to send messages to a channel
983
+ // before sending.
984
+ check(isDefined(stream?.view.channelContent.spaceId), 'synced channel stream not initialized');
985
+ // We check entitlements on the client side for writes to channels. A top-level
986
+ // message post is only permitted if the user has write permissions. If the message
987
+ // is a reaction or redaction, the user may also have react permissions. This is
988
+ // to allow react-only users to react to posts and edit their reactions. We're not
989
+ // concerned with being overly permissive with redactions, as at this time, a user
990
+ // is always allowed to redact their own messages.
991
+ const expectedPermissions = payload.payload.case === 'reaction' || payload.payload.case === 'redaction'
992
+ ? [Permission.React, Permission.Write]
993
+ : [Permission.Write];
994
+ let isEntitled = false;
995
+ for (const permission of expectedPermissions) {
996
+ isEntitled = await this.entitlementsDelegate.isEntitled(stream.view.channelContent.spaceId, streamId, this.userId, permission);
997
+ if (isEntitled) {
998
+ break;
999
+ }
1000
+ }
1001
+ if (!isEntitled) {
1002
+ throw new Error(`user is not entitled to add message to channel (requires [${expectedPermissions.join(',')}] permission)`);
1003
+ }
1004
+ }
1005
+ const tags = opts?.disableTags === true ? undefined : makeTags(payload, stream.view);
1006
+ const cleartext = toBinary(ChannelMessageSchema, payload);
1007
+ let message;
1008
+ const encryptionAlgorithm = stream.view.membershipContent.encryptionAlgorithm;
1009
+ const buffer = toBinary(ChannelMessageSchema, payload);
1010
+ switch (encryptionAlgorithm) {
1011
+ case GroupEncryptionAlgorithmId.HybridGroupEncryption:
1012
+ message = await this.encryptGroupEvent(buffer, streamId, GroupEncryptionAlgorithmId.HybridGroupEncryption);
1013
+ break;
1014
+ case GroupEncryptionAlgorithmId.GroupEncryption:
1015
+ message = await this.encryptGroupEvent(buffer, streamId, GroupEncryptionAlgorithmId.GroupEncryption);
1016
+ break;
1017
+ default: {
1018
+ message = await this.encryptGroupEvent(buffer, streamId, this.defaultGroupEncryptionAlgorithm);
1019
+ }
1020
+ }
1021
+ if (!message) {
1022
+ throw new Error('failed to encrypt message');
1023
+ }
1024
+ message.refEventId = getRefEventIdFromChannelMessage(payload);
1025
+ if (isChannelStreamId(streamId)) {
1026
+ return this.makeEventAndAddToStream(streamId, make_ChannelPayload_Message(message), {
1027
+ method: 'sendMessage',
1028
+ localId,
1029
+ cleartext,
1030
+ tags,
1031
+ });
1032
+ }
1033
+ else if (isDMChannelStreamId(streamId)) {
1034
+ return this.makeEventAndAddToStream(streamId, make_DMChannelPayload_Message(message), {
1035
+ method: 'sendMessageDM',
1036
+ localId,
1037
+ cleartext,
1038
+ tags,
1039
+ });
1040
+ }
1041
+ else if (isGDMChannelStreamId(streamId)) {
1042
+ return this.makeEventAndAddToStream(streamId, make_GDMChannelPayload_Message(message), {
1043
+ method: 'sendMessageGDM',
1044
+ localId,
1045
+ cleartext,
1046
+ tags,
1047
+ });
1048
+ }
1049
+ else {
1050
+ throw new Error(`invalid streamId: ${streamId}`);
1051
+ }
1052
+ }
1053
+ async sendChannelMessage_Text(streamId, payload, opts) {
1054
+ const { content, ...options } = payload;
1055
+ return this.sendChannelMessage(streamId, {
1056
+ payload: {
1057
+ case: 'post',
1058
+ value: {
1059
+ ...options,
1060
+ content: {
1061
+ case: 'text',
1062
+ value: content,
1063
+ },
1064
+ },
1065
+ },
1066
+ }, opts);
1067
+ }
1068
+ async sendChannelMessage_Image(streamId, payload, opts) {
1069
+ const { content, ...options } = payload;
1070
+ return this.sendChannelMessage(streamId, {
1071
+ payload: {
1072
+ case: 'post',
1073
+ value: {
1074
+ ...options,
1075
+ content: {
1076
+ case: 'image',
1077
+ value: content,
1078
+ },
1079
+ },
1080
+ },
1081
+ }, opts);
1082
+ }
1083
+ async sendChannelMessage_GM(streamId, payload, opts) {
1084
+ const { content, ...options } = payload;
1085
+ return this.sendChannelMessage(streamId, {
1086
+ payload: {
1087
+ case: 'post',
1088
+ value: {
1089
+ ...options,
1090
+ content: {
1091
+ case: 'gm',
1092
+ value: content,
1093
+ },
1094
+ },
1095
+ },
1096
+ }, opts);
1097
+ }
1098
+ async sendMediaPayload(creationCookie, last, data, chunkIndex, iv) {
1099
+ const payload = make_MediaPayload_Chunk({
1100
+ data: data,
1101
+ chunkIndex: chunkIndex,
1102
+ iv: iv,
1103
+ });
1104
+ return this.makeMediaEventWithHashAndAddToMediaStream(creationCookie, last, payload);
1105
+ }
1106
+ async getMediaPayload(streamId, secretKey, iv) {
1107
+ const stream = await this.getStream(streamId);
1108
+ const mediaInfo = stream.mediaContent.info;
1109
+ if (!mediaInfo) {
1110
+ return undefined;
1111
+ }
1112
+ const data = new Uint8Array(mediaInfo.chunks.reduce((totalLength, chunk) => totalLength + chunk.length, 0));
1113
+ let offset = 0;
1114
+ mediaInfo.chunks.forEach((chunk) => {
1115
+ data.set(chunk, offset);
1116
+ offset += chunk.length;
1117
+ });
1118
+ return decryptAESGCM(data, secretKey, iv);
1119
+ }
1120
+ async sendChannelMessage_Reaction(streamId, payload, opts) {
1121
+ return this.sendChannelMessage(streamId, {
1122
+ payload: {
1123
+ case: 'reaction',
1124
+ value: payload,
1125
+ },
1126
+ }, opts);
1127
+ }
1128
+ async sendChannelMessage_Redaction(streamId, payload) {
1129
+ const stream = this.stream(streamId);
1130
+ if (!stream) {
1131
+ throw new Error(`stream not found: ${streamId}`);
1132
+ }
1133
+ if (!stream.view.events.has(payload.refEventId)) {
1134
+ throw new Error(`ref event not found: ${payload.refEventId}`);
1135
+ }
1136
+ return this.sendChannelMessage(streamId, {
1137
+ payload: {
1138
+ case: 'redaction',
1139
+ value: payload,
1140
+ },
1141
+ });
1142
+ }
1143
+ async sendChannelMessage_Edit(streamId, refEventId, newPost) {
1144
+ return this.sendChannelMessage(streamId, {
1145
+ payload: {
1146
+ case: 'edit',
1147
+ value: {
1148
+ refEventId: refEventId,
1149
+ post: newPost,
1150
+ },
1151
+ },
1152
+ });
1153
+ }
1154
+ async sendChannelMessage_Edit_Text(streamId, refEventId, payload) {
1155
+ const { content, ...options } = payload;
1156
+ return this.sendChannelMessage_Edit(streamId, refEventId, {
1157
+ ...options,
1158
+ content: {
1159
+ case: 'text',
1160
+ value: content,
1161
+ },
1162
+ });
1163
+ }
1164
+ async redactMessage(streamId, eventId) {
1165
+ const stream = this.stream(streamId);
1166
+ check(isDefined(stream), 'stream not found');
1167
+ return this.makeEventAndAddToStream(streamId, make_ChannelPayload_Redaction(bin_fromHexString(eventId)), {
1168
+ method: 'redactMessage',
1169
+ });
1170
+ }
1171
+ async retrySendMessage(streamId, localId) {
1172
+ const stream = this.stream(streamId);
1173
+ check(isDefined(stream), 'stream not found' + streamId);
1174
+ const event = stream.view.events.get(localId);
1175
+ check(isDefined(event), 'event not found');
1176
+ check(isDefined(event.localEvent), 'event not found');
1177
+ check(event.localEvent.status === 'failed', 'event not in failed state');
1178
+ await this.makeAndSendChannelMessageEvent(streamId, event.localEvent.channelMessage, event.hashStr);
1179
+ }
1180
+ async inviteUser(streamId, userId) {
1181
+ await this.initStream(streamId);
1182
+ check(isDefined(this.userStreamId));
1183
+ return this.makeEventAndAddToStream(this.userStreamId, make_UserPayload_UserMembershipAction({
1184
+ op: MembershipOp.SO_INVITE,
1185
+ userId: addressFromUserId(userId),
1186
+ streamId: streamIdAsBytes(streamId),
1187
+ }), { method: 'inviteUser' });
1188
+ }
1189
+ async joinUser(streamId, userId) {
1190
+ await this.initStream(streamId);
1191
+ check(isDefined(this.userStreamId));
1192
+ return this.makeEventAndAddToStream(this.userStreamId, make_UserPayload_UserMembershipAction({
1193
+ op: MembershipOp.SO_JOIN,
1194
+ userId: addressFromUserId(userId),
1195
+ streamId: streamIdAsBytes(streamId),
1196
+ }), { method: 'inviteUser' });
1197
+ }
1198
+ async joinStream(streamId, opts) {
1199
+ this.logCall('joinStream', streamId);
1200
+ check(isDefined(this.userStreamId));
1201
+ const userStream = this.stream(this.userStreamId);
1202
+ check(isDefined(userStream), 'userStream not found');
1203
+ const streamIdStr = streamIdAsString(streamId);
1204
+ const stream = await this.initStream(streamId);
1205
+ // check your user stream for membership as that's the final source of truth
1206
+ if (userStream.view.userContent.isJoined(streamIdStr)) {
1207
+ this.logError('joinStream: user already a member', streamId);
1208
+ return stream;
1209
+ }
1210
+ // add event to user stream, this triggers events in the target stream
1211
+ await this.makeEventAndAddToStream(this.userStreamId, make_UserPayload_UserMembership({
1212
+ op: MembershipOp.SO_JOIN,
1213
+ streamId: streamIdAsBytes(streamId),
1214
+ streamParentId: stream.view.getContent().getStreamParentIdAsBytes(),
1215
+ }), { method: 'joinStream' });
1216
+ if (opts?.skipWaitForMiniblockConfirmation !== true) {
1217
+ await stream.waitForMembership(MembershipOp.SO_JOIN);
1218
+ }
1219
+ if (opts?.skipWaitForUserStreamUpdate !== true) {
1220
+ if (!userStream.view.userContent.isJoined(streamIdStr)) {
1221
+ await userStream.waitFor('userStreamMembershipChanged', () => userStream.view.userContent.isJoined(streamIdStr));
1222
+ }
1223
+ }
1224
+ return stream;
1225
+ }
1226
+ async leaveStream(streamId) {
1227
+ this.logCall('leaveStream', streamId);
1228
+ check(isDefined(this.userStreamId));
1229
+ if (isSpaceStreamId(streamId)) {
1230
+ const channelIds = this.stream(streamId)?.view.spaceContent.spaceChannelsMetadata.keys() ?? [];
1231
+ const userStream = this.stream(this.userStreamId);
1232
+ for (const channelId of channelIds) {
1233
+ if (userStream?.view.userContent.streamMemberships[channelId]?.op ===
1234
+ MembershipOp.SO_JOIN) {
1235
+ await this.leaveStream(channelId);
1236
+ }
1237
+ }
1238
+ }
1239
+ return this.makeEventAndAddToStream(this.userStreamId, make_UserPayload_UserMembership({
1240
+ op: MembershipOp.SO_LEAVE,
1241
+ streamId: streamIdAsBytes(streamId),
1242
+ }), { method: 'leaveStream' });
1243
+ }
1244
+ async removeUser(streamId, userId) {
1245
+ check(isDefined(this.userStreamId));
1246
+ this.logCall('removeUser', streamId, userId);
1247
+ if (isSpaceStreamId(streamId)) {
1248
+ const channelIds = this.stream(streamId)?.view.spaceContent.spaceChannelsMetadata.keys() ?? [];
1249
+ const userStreamId = makeUserStreamId(userId);
1250
+ const userStream = await this.getStream(userStreamId);
1251
+ for (const channelId of channelIds) {
1252
+ if (userStream.userContent.streamMemberships[channelId]?.op === MembershipOp.SO_JOIN) {
1253
+ try {
1254
+ await this.removeUser(channelId, userId);
1255
+ }
1256
+ catch (error) {
1257
+ this.logError('Failed to remove user from channel', {
1258
+ channelId,
1259
+ userId,
1260
+ error,
1261
+ });
1262
+ }
1263
+ }
1264
+ }
1265
+ }
1266
+ return this.makeEventAndAddToStream(this.userStreamId, make_UserPayload_UserMembershipAction({
1267
+ op: MembershipOp.SO_LEAVE,
1268
+ userId: addressFromUserId(userId),
1269
+ streamId: streamIdAsBytes(streamId),
1270
+ }), { method: 'removeUser' });
1271
+ }
1272
+ // upload transactions made on the base chain
1273
+ async addTransaction(chainId, receipt, content, tags) {
1274
+ check(isDefined(this.userStreamId));
1275
+ const transaction = {
1276
+ receipt: !isSolanaTransactionReceipt(receipt)
1277
+ ? create(BlockchainTransactionReceiptSchema, {
1278
+ chainId: BigInt(chainId),
1279
+ transactionHash: bin_fromHexString(receipt.transactionHash),
1280
+ blockNumber: BigInt(receipt.blockNumber),
1281
+ to: bin_fromHexString(receipt.to),
1282
+ from: bin_fromHexString(receipt.from),
1283
+ logs: receipt.logs.map((log) => create(BlockchainTransactionReceipt_LogSchema, {
1284
+ address: bin_fromHexString(log.address),
1285
+ topics: log.topics.map(bin_fromHexString),
1286
+ data: bin_fromHexString(log.data),
1287
+ })),
1288
+ })
1289
+ : undefined,
1290
+ solanaReceipt: isSolanaTransactionReceipt(receipt)
1291
+ ? create(SolanaBlockchainTransactionReceiptSchema, {
1292
+ ...receipt,
1293
+ })
1294
+ : undefined,
1295
+ content: content ?? { case: undefined },
1296
+ };
1297
+ const event = make_UserPayload_BlockchainTransaction(transaction);
1298
+ return this.makeEventAndAddToStream(this.userStreamId, event, {
1299
+ method: 'addTransaction',
1300
+ tags,
1301
+ });
1302
+ }
1303
+ async addTransaction_Tip(chainId, receipt, event, toUserId, opts) {
1304
+ const stream = this.stream(ensureNoHexPrefix(event.channelId));
1305
+ const tags = opts?.disableTags || !stream?.view
1306
+ ? undefined
1307
+ : makeTipTags(event, toUserId, stream.view);
1308
+ return this.addTransaction(chainId, receipt, {
1309
+ case: 'tip',
1310
+ value: {
1311
+ event: {
1312
+ tokenId: event.tokenId.toBigInt(),
1313
+ currency: bin_fromHexString(event.currency),
1314
+ sender: addressFromUserId(event.sender),
1315
+ receiver: addressFromUserId(event.receiver),
1316
+ amount: event.amount.toBigInt(),
1317
+ messageId: bin_fromHexString(event.messageId),
1318
+ channelId: streamIdAsBytes(event.channelId),
1319
+ },
1320
+ toUserAddress: addressFromUserId(toUserId),
1321
+ },
1322
+ }, tags);
1323
+ }
1324
+ async addTransaction_Transfer(chainId, receipt, event, opts) {
1325
+ const stream = this.stream(streamIdAsString(event.channelId));
1326
+ const tags = opts?.disableTags || !stream?.view ? undefined : makeTransferTags(event, stream.view);
1327
+ return this.addTransaction(chainId, receipt, {
1328
+ case: 'tokenTransfer',
1329
+ value: event,
1330
+ }, tags);
1331
+ }
1332
+ async addTransaction_SpaceReview(chainId, receipt, event, spaceId) {
1333
+ check(event.action !== SpaceReviewAction.None, 'invalid space review event');
1334
+ return this.addTransaction(chainId, receipt, {
1335
+ case: 'spaceReview',
1336
+ value: {
1337
+ action: event.action.valueOf(),
1338
+ spaceAddress: bin_fromHexString(SpaceAddressFromSpaceId(spaceId)),
1339
+ event: {
1340
+ rating: event.rating,
1341
+ user: addressFromUserId(event.user),
1342
+ },
1343
+ },
1344
+ });
1345
+ }
1346
+ async getMiniblocks(streamId, fromInclusive, toExclusive) {
1347
+ const cachedMiniblocks = [];
1348
+ try {
1349
+ for (let i = toExclusive - 1n; i >= fromInclusive; i = i - 1n) {
1350
+ const miniblock = await this.persistenceStore.getMiniblock(streamIdAsString(streamId), i);
1351
+ if (miniblock) {
1352
+ cachedMiniblocks.push(miniblock);
1353
+ toExclusive = i;
1354
+ }
1355
+ else {
1356
+ break;
1357
+ }
1358
+ }
1359
+ cachedMiniblocks.reverse();
1360
+ }
1361
+ catch (error) {
1362
+ this.logError('error getting miniblocks', error);
1363
+ }
1364
+ if (toExclusive === fromInclusive) {
1365
+ return {
1366
+ miniblocks: cachedMiniblocks,
1367
+ terminus: toExclusive === 0n,
1368
+ };
1369
+ }
1370
+ const { miniblocks, terminus } = await getMiniblocks(this.rpcClient, streamId, fromInclusive, toExclusive, this.opts?.unpackEnvelopeOpts);
1371
+ await this.persistenceStore.saveMiniblocks(streamIdAsString(streamId), miniblocks, 'backward');
1372
+ return {
1373
+ terminus: terminus,
1374
+ miniblocks: [...miniblocks, ...cachedMiniblocks],
1375
+ };
1376
+ }
1377
+ async scrollback(streamId) {
1378
+ const currentRequest = this.getScrollbackRequests.get(streamId);
1379
+ if (currentRequest) {
1380
+ return currentRequest;
1381
+ }
1382
+ const _scrollback = async () => {
1383
+ const stream = this.stream(streamId);
1384
+ check(isDefined(stream), `stream not found: ${streamId}`);
1385
+ check(isDefined(stream.view.miniblockInfo), `stream not initialized: ${streamId}`);
1386
+ if (stream.view.miniblockInfo.terminusReached) {
1387
+ this.logCall('scrollback', streamId, 'terminus reached');
1388
+ return { terminus: true, firstEvent: stream.view.timeline.at(0) };
1389
+ }
1390
+ check(stream.view.miniblockInfo.min >= stream.view.prevSnapshotMiniblockNum);
1391
+ this.logCall('scrollback', {
1392
+ streamId,
1393
+ miniblockInfo: stream.view.miniblockInfo,
1394
+ prevSnapshotMiniblockNum: stream.view.prevSnapshotMiniblockNum,
1395
+ });
1396
+ const toExclusive = stream.view.miniblockInfo.min;
1397
+ const fromInclusive = stream.view.prevSnapshotMiniblockNum;
1398
+ const response = await this.getMiniblocks(streamId, fromInclusive, toExclusive);
1399
+ const eventIds = response.miniblocks.flatMap((m) => m.events.map((e) => e.hashStr));
1400
+ const cleartexts = await this.persistenceStore.getCleartexts(eventIds);
1401
+ // a race may occur here: if the state view has been reinitialized during the scrollback
1402
+ // request, we need to discard the new miniblocks.
1403
+ if ((stream.view.miniblockInfo?.min ?? -1n) === toExclusive) {
1404
+ stream.prependEvents(response.miniblocks, cleartexts, response.terminus);
1405
+ return { terminus: response.terminus, firstEvent: stream.view.timeline.at(0) };
1406
+ }
1407
+ return { terminus: false, firstEvent: stream.view.timeline.at(0) };
1408
+ };
1409
+ try {
1410
+ const request = _scrollback();
1411
+ this.getScrollbackRequests.set(streamId, request);
1412
+ return await request;
1413
+ }
1414
+ finally {
1415
+ this.getScrollbackRequests.delete(streamId);
1416
+ }
1417
+ }
1418
+ /**
1419
+ * Get the list of active devices for all users in the room
1420
+ *
1421
+ *
1422
+ * @returns Promise which resolves to `null`, or an array whose
1423
+ * first element is a {@link DeviceInfoMap} indicating
1424
+ * the devices that messages should be encrypted to, and whose second
1425
+ * element is a map from userId to deviceId to data indicating the devices
1426
+ * that are in the room but that have been blocked.
1427
+ */
1428
+ async getDevicesInStream(stream_id) {
1429
+ let stream;
1430
+ stream = this.stream(stream_id)?.view;
1431
+ if (!stream || !stream.isInitialized) {
1432
+ stream = await this.getStream(stream_id);
1433
+ }
1434
+ if (!stream) {
1435
+ this.logError(`stream for room ${stream_id} not found`);
1436
+ return {};
1437
+ }
1438
+ const members = Array.from(stream.getUsersEntitledToKeyExchange());
1439
+ this.logCall(`Encrypting for users (shouldEncryptForInvitedMembers:`, members.map((u) => `${u} (${MembershipOp[MembershipOp.SO_JOIN]})`));
1440
+ const info = await this.downloadUserDeviceInfo(members);
1441
+ this.logCall('keys: ', Object.keys(info).map((key) => `${key} (${info[key].length})`));
1442
+ return info;
1443
+ }
1444
+ async getMiniblockInfo(streamId) {
1445
+ let streamView = this.stream(streamId)?.view;
1446
+ // if we don't have a local copy, or if it's just not initialized, fetch the latest
1447
+ if (!streamView || !streamView.isInitialized) {
1448
+ streamView = await this.getStream(streamId);
1449
+ }
1450
+ check(isDefined(streamView), `stream not found: ${streamId}`);
1451
+ check(isDefined(streamView.miniblockInfo), `stream not initialized: ${streamId}`);
1452
+ check(isDefined(streamView.prevMiniblockHash), `prevMiniblockHash not found: ${streamId}`);
1453
+ return {
1454
+ miniblockNum: streamView.miniblockInfo.max,
1455
+ miniblockHash: streamView.prevMiniblockHash,
1456
+ };
1457
+ }
1458
+ async downloadNewInboxMessages() {
1459
+ this.logCall('downloadNewInboxMessages');
1460
+ check(isDefined(this.userInboxStreamId));
1461
+ const stream = this.stream(this.userInboxStreamId);
1462
+ check(isDefined(stream));
1463
+ check(isDefined(stream.view.miniblockInfo));
1464
+ if (stream.view.miniblockInfo.terminusReached) {
1465
+ return;
1466
+ }
1467
+ const deviceSummary = stream.view.userInboxContent.deviceSummary[this.userDeviceKey().deviceKey];
1468
+ if (!deviceSummary) {
1469
+ return;
1470
+ }
1471
+ if (deviceSummary.lowerBound < stream.view.miniblockInfo.min) {
1472
+ const toExclusive = stream.view.miniblockInfo.min;
1473
+ const fromInclusive = deviceSummary.lowerBound;
1474
+ const response = await this.getMiniblocks(this.userInboxStreamId, fromInclusive, toExclusive);
1475
+ const eventIds = response.miniblocks.flatMap((m) => m.events.map((e) => e.hashStr));
1476
+ const cleartexts = await this.persistenceStore.getCleartexts(eventIds);
1477
+ stream.prependEvents(response.miniblocks, cleartexts, response.terminus);
1478
+ }
1479
+ }
1480
+ async downloadUserDeviceInfo(userIds) {
1481
+ // always fetch keys for arbitrarily small channels/dms/gdms. For large channels only
1482
+ // fetch keys if you don't already have keys, extended keysharing should work for those cases
1483
+ const forceDownload = userIds.length <= 10;
1484
+ const promises = userIds.map(async (userId) => {
1485
+ const streamId = makeUserMetadataStreamId(userId);
1486
+ try {
1487
+ // also always download your own keys so you always share to your most up to date devices
1488
+ if (!forceDownload && userId !== this.userId) {
1489
+ const devicesFromStore = await this.cryptoStore.getUserDevices(userId);
1490
+ if (devicesFromStore.length > 0) {
1491
+ return { userId, devices: devicesFromStore };
1492
+ }
1493
+ }
1494
+ // return latest 10 device keys
1495
+ const deviceLookback = 10;
1496
+ const stream = await this.getStream(streamId);
1497
+ const userDevices = stream.userMetadataContent.deviceKeys.slice(-deviceLookback);
1498
+ await this.cryptoStore.saveUserDevices(userId, userDevices);
1499
+ return { userId, devices: userDevices };
1500
+ }
1501
+ catch (e) {
1502
+ this.logError('Error downloading user device keys', e);
1503
+ return { userId, devices: [] };
1504
+ }
1505
+ });
1506
+ return (await Promise.all(promises)).reduce((acc, current) => {
1507
+ acc[current.userId] = current.devices;
1508
+ return acc;
1509
+ }, {});
1510
+ }
1511
+ async knownDevicesForUserId(userId) {
1512
+ return await this.cryptoStore.getUserDevices(userId);
1513
+ }
1514
+ async makeEventAndAddToStream(streamId, payload, options = {}) {
1515
+ // TODO: filter this.logged payload for PII reasons
1516
+ this.logCall('await makeEventAndAddToStream', options.method, streamId, payload, options.localId, options.optional);
1517
+ assert(this.userStreamId !== undefined, 'userStreamId must be set');
1518
+ const stream = this.streams.get(streamId);
1519
+ assert(stream !== undefined, 'unknown stream ' + streamIdAsString(streamId));
1520
+ const prevHash = stream.view.prevMiniblockHash;
1521
+ assert(isDefined(prevHash), 'no prev miniblock hash for stream ' + streamIdAsString(streamId));
1522
+ const { eventId, error } = await this.makeEventWithHashAndAddToStream(streamId, payload, prevHash, options.optional, options.localId, options.cleartext, options.tags);
1523
+ return { eventId, error };
1524
+ }
1525
+ async makeEventWithHashAndAddToStream(streamId, payload, prevMiniblockHash, optional, localId, cleartext, tags, retryCount) {
1526
+ const streamIdStr = streamIdAsString(streamId);
1527
+ check(isDefined(streamIdStr) && streamIdStr !== '', 'streamId must be defined');
1528
+ const event = await makeEvent(this.signerContext, payload, prevMiniblockHash, tags);
1529
+ const eventId = bin_toHexString(event.hash);
1530
+ if (localId) {
1531
+ // when we have a localId, we need to update the local event with the eventId
1532
+ const stream = this.streams.get(streamId);
1533
+ assert(stream !== undefined, 'unknown stream ' + streamIdStr);
1534
+ stream.updateLocalEvent(localId, eventId, 'sending');
1535
+ }
1536
+ if (cleartext) {
1537
+ // if we have cleartext, save it so we don't have to re-decrypt it later
1538
+ await this.persistenceStore.saveCleartext(eventId, cleartext);
1539
+ }
1540
+ try {
1541
+ const { error } = await this.rpcClient.addEvent({
1542
+ streamId: streamIdAsBytes(streamId),
1543
+ event,
1544
+ optional,
1545
+ });
1546
+ if (localId) {
1547
+ const stream = this.streams.get(streamId);
1548
+ stream?.updateLocalEvent(localId, eventId, 'sent');
1549
+ }
1550
+ return { prevMiniblockHash, eventId, error };
1551
+ }
1552
+ catch (err) {
1553
+ // custom retry logic for addEvent
1554
+ // if we send up a stale prevMiniblockHash, the server will return a BAD_PREV_MINIBLOCK_HASH
1555
+ // error and include the expected hash in the error message
1556
+ // if we had a localEventId, pass the last id so the ui can continue to update to the latest hash
1557
+ retryCount = retryCount ?? 0;
1558
+ if (errorContains(err, Err.BAD_PREV_MINIBLOCK_HASH) && retryCount < 3) {
1559
+ const expectedHash = getRpcErrorProperty(err, 'expected');
1560
+ this.logInfo('RETRYING event after BAD_PREV_MINIBLOCK_HASH response', {
1561
+ syncStats: this.streams.stats(),
1562
+ retryCount,
1563
+ prevMiniblockHash,
1564
+ expectedHash,
1565
+ });
1566
+ check(isDefined(expectedHash), 'expected hash not found in error');
1567
+ return await this.makeEventWithHashAndAddToStream(streamId, payload, bin_fromHexString(expectedHash), optional, isDefined(localId) ? eventId : undefined, cleartext, tags, retryCount + 1);
1568
+ }
1569
+ else {
1570
+ if (localId) {
1571
+ const stream = this.streams.get(streamId);
1572
+ stream?.updateLocalEvent(localId, eventId, 'failed');
1573
+ }
1574
+ throw err;
1575
+ }
1576
+ }
1577
+ }
1578
+ // makeMediaEventWithHashAndAddToMediaStream is used for uploading media chunks to the media stream.
1579
+ // This function uses media stream specific RPC endpoints to upload media chunks.
1580
+ // These endpoints are optimized for media uploads and are not used for general stream events.
1581
+ async makeMediaEventWithHashAndAddToMediaStream(creationCookie, last, payload) {
1582
+ const streamIdStr = streamIdAsString(creationCookie.streamId);
1583
+ check(isDefined(streamIdStr) && streamIdStr !== '', 'streamId must be defined');
1584
+ const event = await makeEvent(this.signerContext, payload, creationCookie.prevMiniblockHash);
1585
+ const resp = await this.rpcClient.addMediaEvent({
1586
+ event,
1587
+ creationCookie,
1588
+ last,
1589
+ });
1590
+ check(isDefined(resp.creationCookie), 'creationCookie not found in response');
1591
+ return { creationCookie: resp.creationCookie };
1592
+ }
1593
+ async getStreamLastMiniblockHash(streamId) {
1594
+ const r = await this.rpcClient.getLastMiniblockHash({ streamId: streamIdAsBytes(streamId) });
1595
+ return r.hash;
1596
+ }
1597
+ async initCrypto(opts) {
1598
+ this.logCall('initCrypto');
1599
+ if (this.cryptoBackend) {
1600
+ this.logCall('Attempt to re-init crypto backend, ignoring');
1601
+ return;
1602
+ }
1603
+ check(this.userId !== undefined, 'userId must be set to init crypto');
1604
+ await this.cryptoStore.initialize();
1605
+ const crypto = new GroupEncryptionCrypto(this, this.cryptoStore);
1606
+ await crypto.init(opts);
1607
+ this.cryptoBackend = crypto;
1608
+ this.decryptionExtensions = new ClientDecryptionExtensions(this, crypto, this.entitlementsDelegate, this.userId, this.userDeviceKey(), this.opts?.unpackEnvelopeOpts, this.logId);
1609
+ }
1610
+ /**
1611
+ * Resets crypto backend and creates a new encryption account, uploading device keys to UserDeviceKey stream.
1612
+ */
1613
+ async resetCrypto() {
1614
+ this.logCall('resetCrypto');
1615
+ if (this.userId == undefined) {
1616
+ throw new Error('userId must be set to reset crypto');
1617
+ }
1618
+ this.cryptoBackend = undefined;
1619
+ await this.decryptionExtensions?.stop();
1620
+ this.decryptionExtensions = undefined;
1621
+ await this.cryptoStore.deleteAccount(this.userId);
1622
+ await this.initCrypto();
1623
+ await this.uploadDeviceKeys();
1624
+ }
1625
+ async uploadDeviceKeys() {
1626
+ check(isDefined(this.cryptoBackend), 'crypto backend not initialized');
1627
+ this.logCall('initCrypto:: uploading device keys...');
1628
+ check(isDefined(this.userMetadataStreamId));
1629
+ const stream = this.stream(this.userMetadataStreamId);
1630
+ check(isDefined(stream), 'device key stream not found');
1631
+ return this.makeEventAndAddToStream(this.userMetadataStreamId, make_UserMetadataPayload_EncryptionDevice({
1632
+ ...this.userDeviceKey(),
1633
+ }), { method: 'userDeviceKey' });
1634
+ }
1635
+ async ackInboxStream() {
1636
+ check(isDefined(this.userInboxStreamId), 'user to device stream not found');
1637
+ check(isDefined(this.cryptoBackend), 'crypto backend not initialized');
1638
+ const inboxStream = this.streams.get(this.userInboxStreamId);
1639
+ check(isDefined(inboxStream), 'user to device stream not found');
1640
+ const miniblockNum = inboxStream?.view.miniblockInfo?.max;
1641
+ check(isDefined(miniblockNum), 'miniblockNum not found');
1642
+ this.logCall('ackInboxStream:: acking received keys...');
1643
+ const previousAck = inboxStream.view.userInboxContent.deviceSummary[this.userDeviceKey().deviceKey];
1644
+ if (previousAck && previousAck.lowerBound >= miniblockNum) {
1645
+ this.logCall('ackInboxStream:: already acked', previousAck, 'miniblockNum:', miniblockNum);
1646
+ return;
1647
+ }
1648
+ await this.makeEventAndAddToStream(this.userInboxStreamId, make_UserInboxPayload_Ack({
1649
+ deviceKey: this.userDeviceKey().deviceKey,
1650
+ miniblockNum,
1651
+ }));
1652
+ }
1653
+ setHighPriorityStreams(streamIds) {
1654
+ this.logCall('setHighPriorityStreams', streamIds);
1655
+ this.decryptionExtensions?.setHighPriorityStreams(streamIds);
1656
+ this.syncedStreamsExtensions?.setHighPriorityStreams(streamIds);
1657
+ this.streams.setHighPriorityStreams(streamIds);
1658
+ }
1659
+ async ensureOutboundSession(streamId, opts) {
1660
+ check(isDefined(this.cryptoBackend), 'crypto backend not initialized');
1661
+ return this.cryptoBackend.ensureOutboundSession(streamId, this.defaultGroupEncryptionAlgorithm, opts);
1662
+ }
1663
+ /**
1664
+ * decrypts and updates the decrypted event
1665
+ */
1666
+ async decryptGroupEvent(streamId, eventId, kind, // kind of data
1667
+ encryptedData) {
1668
+ this.logCall('decryptGroupEvent', streamId, eventId, kind, encryptedData);
1669
+ const stream = this.stream(streamId);
1670
+ check(isDefined(stream), 'stream not found');
1671
+ check(isEncryptedContentKind(kind), `invalid kind ${kind}`);
1672
+ const cleartext = await this.cleartextForGroupEvent(streamId, eventId, encryptedData);
1673
+ const decryptedContent = toDecryptedContent(kind, encryptedData.version, cleartext);
1674
+ stream.updateDecryptedContent(eventId, decryptedContent);
1675
+ }
1676
+ async cleartextForGroupEvent(streamId, eventId, encryptedData) {
1677
+ const cached = await this.persistenceStore.getCleartext(eventId);
1678
+ if (cached) {
1679
+ this.logDebug('Cache hit for cleartext', eventId);
1680
+ return cached;
1681
+ }
1682
+ this.logDebug('Cache miss for cleartext', eventId);
1683
+ if (!this.cryptoBackend) {
1684
+ throw new Error('crypto backend not initialized');
1685
+ }
1686
+ const cleartext = await this.cryptoBackend.decryptGroupEvent(streamId, encryptedData);
1687
+ await this.persistenceStore.saveCleartext(eventId, cleartext);
1688
+ return cleartext;
1689
+ }
1690
+ async encryptAndShareGroupSessions(inStreamId, sessions, toDevices, algorithm) {
1691
+ const streamIdStr = streamIdAsString(inStreamId);
1692
+ const streamIdBytes = streamIdAsBytes(inStreamId);
1693
+ check(isDefined(this.cryptoBackend), "crypto backend isn't initialized");
1694
+ check(sessions.length >= 0, 'no sessions to encrypt');
1695
+ check(new Set(sessions.map((s) => s.streamId)).size === 1, 'sessions should all be from the same stream');
1696
+ check(sessions[0].algorithm === algorithm, 'algorithm mismatch');
1697
+ check(new Set(sessions.map((s) => s.algorithm)).size === 1, 'all sessions should be the same algorithm');
1698
+ check(sessions[0].streamId === streamIdStr, 'streamId mismatch');
1699
+ this.logCall('share', { from: this.userId, to: toDevices });
1700
+ const userDevice = this.userDeviceKey();
1701
+ const sessionIds = sessions.map((session) => session.sessionId);
1702
+ const payload = makeSessionKeys(sessions);
1703
+ const payloadClearText = toJsonString(SessionKeysSchema, payload);
1704
+ const promises = Object.entries(toDevices).map(async ([userId, deviceKeys]) => {
1705
+ try {
1706
+ const ciphertext = await this.encryptWithDeviceKeys(payloadClearText, deviceKeys);
1707
+ if (Object.keys(ciphertext).length === 0) {
1708
+ this.logCall('encryptAndShareGroupSessions: no ciphertext to send', userId);
1709
+ return;
1710
+ }
1711
+ const toStreamId = makeUserInboxStreamId(userId);
1712
+ const miniblockHash = await this.getStreamLastMiniblockHash(toStreamId);
1713
+ this.logCall("encryptAndShareGroupSessions: sent to user's devices", {
1714
+ toStreamId,
1715
+ deviceKeys: deviceKeys.map((d) => d.deviceKey).join(','),
1716
+ });
1717
+ await this.makeEventWithHashAndAddToStream(toStreamId, make_UserInboxPayload_GroupEncryptionSessions({
1718
+ streamId: streamIdBytes,
1719
+ senderKey: userDevice.deviceKey,
1720
+ sessionIds: sessionIds,
1721
+ ciphertexts: ciphertext,
1722
+ algorithm: algorithm,
1723
+ }), miniblockHash);
1724
+ }
1725
+ catch (error) {
1726
+ this.logError('encryptAndShareGroupSessions: ERROR', error);
1727
+ return undefined;
1728
+ }
1729
+ });
1730
+ await Promise.all(promises);
1731
+ }
1732
+ // Encrypt event using GroupEncryption.
1733
+ encryptGroupEvent(event, streamId, algorithm) {
1734
+ if (!this.cryptoBackend) {
1735
+ throw new Error('crypto backend not initialized');
1736
+ }
1737
+ return this.cryptoBackend.encryptGroupEvent(streamId, event, algorithm);
1738
+ }
1739
+ async encryptWithDeviceKeys(payloadClearText, deviceKeys) {
1740
+ check(isDefined(this.cryptoBackend), 'crypto backend not initialized');
1741
+ // Don't encrypt to our own device
1742
+ return this.cryptoBackend.encryptWithDeviceKeys(payloadClearText, deviceKeys.filter((key) => key.deviceKey !== this.userDeviceKey().deviceKey));
1743
+ }
1744
+ // Used during testing
1745
+ userDeviceKey() {
1746
+ if (!this.cryptoBackend) {
1747
+ throw new Error('cryptoBackend not initialized');
1748
+ }
1749
+ return this.cryptoBackend.getUserDevice();
1750
+ }
1751
+ async debugForceMakeMiniblock(streamId, opts = {}) {
1752
+ await this.rpcClient.info({
1753
+ debug: ['make_miniblock', streamId, opts.forceSnapshot === true ? 'true' : 'false'],
1754
+ });
1755
+ }
1756
+ async debugForceAddEvent(streamId, event) {
1757
+ const jsonStr = toJsonString(EnvelopeSchema, event);
1758
+ await this.rpcClient.info({ debug: ['add_event', streamId, jsonStr] });
1759
+ }
1760
+ async debugDropStream(syncId, streamId) {
1761
+ await this.rpcClient.info({ debug: ['drop_stream', syncId, streamId] });
1762
+ }
1763
+ }
1764
+ function ensureNoHexPrefix(value) {
1765
+ return value.startsWith('0x') ? value.slice(2) : value;
1766
+ }
1767
+ //# sourceMappingURL=client.js.map