@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.
- package/README.md +29 -0
- package/dist/check.d.ts +31 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +44 -0
- package/dist/check.js.map +1 -0
- package/dist/client.d.ts +333 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1767 -0
- package/dist/client.js.map +1 -0
- package/dist/clientDecryptionExtensions.d.ts +44 -0
- package/dist/clientDecryptionExtensions.d.ts.map +1 -0
- package/dist/clientDecryptionExtensions.js +256 -0
- package/dist/clientDecryptionExtensions.js.map +1 -0
- package/dist/crypto_utils.d.ts +15 -0
- package/dist/crypto_utils.d.ts.map +1 -0
- package/dist/crypto_utils.js +99 -0
- package/dist/crypto_utils.js.map +1 -0
- package/dist/encryptedContentTypes.d.ts +31 -0
- package/dist/encryptedContentTypes.d.ts.map +1 -0
- package/dist/encryptedContentTypes.js +73 -0
- package/dist/encryptedContentTypes.js.map +1 -0
- package/dist/id.d.ts +54 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +190 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/makeAuthenticationRpcClient.d.ts +8 -0
- package/dist/makeAuthenticationRpcClient.d.ts.map +1 -0
- package/dist/makeAuthenticationRpcClient.js +39 -0
- package/dist/makeAuthenticationRpcClient.js.map +1 -0
- package/dist/makeNotificationRpcClient.d.ts +8 -0
- package/dist/makeNotificationRpcClient.d.ts.map +1 -0
- package/dist/makeNotificationRpcClient.js +40 -0
- package/dist/makeNotificationRpcClient.js.map +1 -0
- package/dist/makeRiverRpcClient.d.ts +6 -0
- package/dist/makeRiverRpcClient.d.ts.map +1 -0
- package/dist/makeRiverRpcClient.js +9 -0
- package/dist/makeRiverRpcClient.js.map +1 -0
- package/dist/makeStreamRpcClient.d.ts +20 -0
- package/dist/makeStreamRpcClient.d.ts.map +1 -0
- package/dist/makeStreamRpcClient.js +91 -0
- package/dist/makeStreamRpcClient.js.map +1 -0
- package/dist/memberMetadata_DisplayNames.d.ts +27 -0
- package/dist/memberMetadata_DisplayNames.d.ts.map +1 -0
- package/dist/memberMetadata_DisplayNames.js +96 -0
- package/dist/memberMetadata_DisplayNames.js.map +1 -0
- package/dist/memberMetadata_EnsAddresses.d.ts +25 -0
- package/dist/memberMetadata_EnsAddresses.d.ts.map +1 -0
- package/dist/memberMetadata_EnsAddresses.js +86 -0
- package/dist/memberMetadata_EnsAddresses.js.map +1 -0
- package/dist/memberMetadata_Nft.d.ts +31 -0
- package/dist/memberMetadata_Nft.d.ts.map +1 -0
- package/dist/memberMetadata_Nft.js +95 -0
- package/dist/memberMetadata_Nft.js.map +1 -0
- package/dist/memberMetadata_Usernames.d.ts +33 -0
- package/dist/memberMetadata_Usernames.d.ts.map +1 -0
- package/dist/memberMetadata_Usernames.js +152 -0
- package/dist/memberMetadata_Usernames.js.map +1 -0
- package/dist/migrations/migrateSnapshot.d.ts +3 -0
- package/dist/migrations/migrateSnapshot.d.ts.map +1 -0
- package/dist/migrations/migrateSnapshot.js +17 -0
- package/dist/migrations/migrateSnapshot.js.map +1 -0
- package/dist/migrations/snapshotMigration0000.d.ts +3 -0
- package/dist/migrations/snapshotMigration0000.d.ts.map +1 -0
- package/dist/migrations/snapshotMigration0000.js +5 -0
- package/dist/migrations/snapshotMigration0000.js.map +1 -0
- package/dist/migrations/snapshotMigration0001.d.ts +3 -0
- package/dist/migrations/snapshotMigration0001.d.ts.map +1 -0
- package/dist/migrations/snapshotMigration0001.js +40 -0
- package/dist/migrations/snapshotMigration0001.js.map +1 -0
- package/dist/migrations/snapshotMigration0002.d.ts +3 -0
- package/dist/migrations/snapshotMigration0002.d.ts.map +1 -0
- package/dist/migrations/snapshotMigration0002.js +23 -0
- package/dist/migrations/snapshotMigration0002.js.map +1 -0
- package/dist/notificationService.d.ts +17 -0
- package/dist/notificationService.d.ts.map +1 -0
- package/dist/notificationService.js +48 -0
- package/dist/notificationService.js.map +1 -0
- package/dist/observable/observable.d.ts +28 -0
- package/dist/observable/observable.d.ts.map +1 -0
- package/dist/observable/observable.js +57 -0
- package/dist/observable/observable.js.map +1 -0
- package/dist/observable/persistedObservable.d.ts +37 -0
- package/dist/observable/persistedObservable.d.ts.map +1 -0
- package/dist/observable/persistedObservable.js +77 -0
- package/dist/observable/persistedObservable.js.map +1 -0
- package/dist/persistenceStore.d.ts +71 -0
- package/dist/persistenceStore.d.ts.map +1 -0
- package/dist/persistenceStore.js +366 -0
- package/dist/persistenceStore.js.map +1 -0
- package/dist/riverConfig.d.ts +23 -0
- package/dist/riverConfig.d.ts.map +1 -0
- package/dist/riverConfig.js +111 -0
- package/dist/riverConfig.js.map +1 -0
- package/dist/riverDbManager.d.ts +5 -0
- package/dist/riverDbManager.d.ts.map +1 -0
- package/dist/riverDbManager.js +7 -0
- package/dist/riverDbManager.js.map +1 -0
- package/dist/rpcCommon.d.ts +9 -0
- package/dist/rpcCommon.d.ts.map +1 -0
- package/dist/rpcCommon.js +14 -0
- package/dist/rpcCommon.js.map +1 -0
- package/dist/rpcInterceptors.d.ts +20 -0
- package/dist/rpcInterceptors.d.ts.map +1 -0
- package/dist/rpcInterceptors.js +369 -0
- package/dist/rpcInterceptors.js.map +1 -0
- package/dist/sign.d.ts +41 -0
- package/dist/sign.d.ts.map +1 -0
- package/dist/sign.js +268 -0
- package/dist/sign.js.map +1 -0
- package/dist/signerContext.d.ts +60 -0
- package/dist/signerContext.d.ts.map +1 -0
- package/dist/signerContext.js +101 -0
- package/dist/signerContext.js.map +1 -0
- package/dist/store/store.d.ts +22 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +165 -0
- package/dist/store/store.js.map +1 -0
- package/dist/stream.d.ts +47 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +111 -0
- package/dist/stream.js.map +1 -0
- package/dist/streamEvents.d.ts +86 -0
- package/dist/streamEvents.d.ts.map +1 -0
- package/dist/streamEvents.js +2 -0
- package/dist/streamEvents.js.map +1 -0
- package/dist/streamStateView.d.ts +119 -0
- package/dist/streamStateView.d.ts.map +1 -0
- package/dist/streamStateView.js +527 -0
- package/dist/streamStateView.js.map +1 -0
- package/dist/streamStateView_AbstractContent.d.ts +20 -0
- package/dist/streamStateView_AbstractContent.d.ts.map +1 -0
- package/dist/streamStateView_AbstractContent.js +41 -0
- package/dist/streamStateView_AbstractContent.js.map +1 -0
- package/dist/streamStateView_Channel.d.ts +20 -0
- package/dist/streamStateView_Channel.d.ts.map +1 -0
- package/dist/streamStateView_Channel.js +65 -0
- package/dist/streamStateView_Channel.js.map +1 -0
- package/dist/streamStateView_ChannelMetadata.d.ts +22 -0
- package/dist/streamStateView_ChannelMetadata.d.ts.map +1 -0
- package/dist/streamStateView_ChannelMetadata.js +57 -0
- package/dist/streamStateView_ChannelMetadata.js.map +1 -0
- package/dist/streamStateView_DMChannel.d.ts +22 -0
- package/dist/streamStateView_DMChannel.d.ts.map +1 -0
- package/dist/streamStateView_DMChannel.js +78 -0
- package/dist/streamStateView_DMChannel.js.map +1 -0
- package/dist/streamStateView_GDMChannel.d.ts +22 -0
- package/dist/streamStateView_GDMChannel.d.ts.map +1 -0
- package/dist/streamStateView_GDMChannel.js +82 -0
- package/dist/streamStateView_GDMChannel.js.map +1 -0
- package/dist/streamStateView_Media.d.ts +20 -0
- package/dist/streamStateView_Media.d.ts.map +1 -0
- package/dist/streamStateView_Media.js +54 -0
- package/dist/streamStateView_Media.js.map +1 -0
- package/dist/streamStateView_MemberMetadata.d.ts +51 -0
- package/dist/streamStateView_MemberMetadata.d.ts.map +1 -0
- package/dist/streamStateView_MemberMetadata.js +97 -0
- package/dist/streamStateView_MemberMetadata.js.map +1 -0
- package/dist/streamStateView_Members.d.ts +70 -0
- package/dist/streamStateView_Members.d.ts.map +1 -0
- package/dist/streamStateView_Members.js +409 -0
- package/dist/streamStateView_Members.js.map +1 -0
- package/dist/streamStateView_Members_Membership.d.ts +29 -0
- package/dist/streamStateView_Members_Membership.d.ts.map +1 -0
- package/dist/streamStateView_Members_Membership.js +117 -0
- package/dist/streamStateView_Members_Membership.js.map +1 -0
- package/dist/streamStateView_Members_Solicitations.d.ts +15 -0
- package/dist/streamStateView_Members_Solicitations.d.ts.map +1 -0
- package/dist/streamStateView_Members_Solicitations.js +49 -0
- package/dist/streamStateView_Members_Solicitations.js.map +1 -0
- package/dist/streamStateView_Space.d.ts +34 -0
- package/dist/streamStateView_Space.d.ts.map +1 -0
- package/dist/streamStateView_Space.js +190 -0
- package/dist/streamStateView_Space.js.map +1 -0
- package/dist/streamStateView_UnknownContent.d.ts +11 -0
- package/dist/streamStateView_UnknownContent.d.ts.map +1 -0
- package/dist/streamStateView_UnknownContent.js +15 -0
- package/dist/streamStateView_UnknownContent.js.map +1 -0
- package/dist/streamStateView_User.d.ts +26 -0
- package/dist/streamStateView_User.d.ts.map +1 -0
- package/dist/streamStateView_User.js +154 -0
- package/dist/streamStateView_User.js.map +1 -0
- package/dist/streamStateView_UserInbox.d.ts +17 -0
- package/dist/streamStateView_UserInbox.d.ts.map +1 -0
- package/dist/streamStateView_UserInbox.js +70 -0
- package/dist/streamStateView_UserInbox.js.map +1 -0
- package/dist/streamStateView_UserMetadata.d.ts +27 -0
- package/dist/streamStateView_UserMetadata.d.ts.map +1 -0
- package/dist/streamStateView_UserMetadata.js +146 -0
- package/dist/streamStateView_UserMetadata.js.map +1 -0
- package/dist/streamStateView_UserSettings.d.ts +32 -0
- package/dist/streamStateView_UserSettings.d.ts.map +1 -0
- package/dist/streamStateView_UserSettings.js +112 -0
- package/dist/streamStateView_UserSettings.js.map +1 -0
- package/dist/streamUtils.d.ts +15 -0
- package/dist/streamUtils.d.ts.map +1 -0
- package/dist/streamUtils.js +112 -0
- package/dist/streamUtils.js.map +1 -0
- package/dist/sync-agent/db.d.ts +19 -0
- package/dist/sync-agent/db.d.ts.map +1 -0
- package/dist/sync-agent/db.js +36 -0
- package/dist/sync-agent/db.js.map +1 -0
- package/dist/sync-agent/dms/dms.d.ts +24 -0
- package/dist/sync-agent/dms/dms.d.ts.map +1 -0
- package/dist/sync-agent/dms/dms.js +60 -0
- package/dist/sync-agent/dms/dms.js.map +1 -0
- package/dist/sync-agent/dms/models/dm.d.ts +59 -0
- package/dist/sync-agent/dms/models/dm.d.ts.map +1 -0
- package/dist/sync-agent/dms/models/dm.js +140 -0
- package/dist/sync-agent/dms/models/dm.js.map +1 -0
- package/dist/sync-agent/entitlements/entitlements.d.ts +10 -0
- package/dist/sync-agent/entitlements/entitlements.d.ts.map +1 -0
- package/dist/sync-agent/entitlements/entitlements.js +23 -0
- package/dist/sync-agent/entitlements/entitlements.js.map +1 -0
- package/dist/sync-agent/gdms/gdms.d.ts +23 -0
- package/dist/sync-agent/gdms/gdms.d.ts.map +1 -0
- package/dist/sync-agent/gdms/gdms.js +56 -0
- package/dist/sync-agent/gdms/gdms.js.map +1 -0
- package/dist/sync-agent/gdms/models/gdm.d.ts +59 -0
- package/dist/sync-agent/gdms/models/gdm.d.ts.map +1 -0
- package/dist/sync-agent/gdms/models/gdm.js +138 -0
- package/dist/sync-agent/gdms/models/gdm.js.map +1 -0
- package/dist/sync-agent/members/members.d.ts +32 -0
- package/dist/sync-agent/members/members.d.ts.map +1 -0
- package/dist/sync-agent/members/members.js +143 -0
- package/dist/sync-agent/members/members.js.map +1 -0
- package/dist/sync-agent/members/models/member.d.ts +66 -0
- package/dist/sync-agent/members/models/member.d.ts.map +1 -0
- package/dist/sync-agent/members/models/member.js +131 -0
- package/dist/sync-agent/members/models/member.js.map +1 -0
- package/dist/sync-agent/members/models/myself.d.ts +20 -0
- package/dist/sync-agent/members/models/myself.d.ts.map +1 -0
- package/dist/sync-agent/members/models/myself.js +97 -0
- package/dist/sync-agent/members/models/myself.js.map +1 -0
- package/dist/sync-agent/river-connection/models/authStatus.d.ts +18 -0
- package/dist/sync-agent/river-connection/models/authStatus.d.ts.map +1 -0
- package/dist/sync-agent/river-connection/models/authStatus.js +19 -0
- package/dist/sync-agent/river-connection/models/authStatus.js.map +1 -0
- package/dist/sync-agent/river-connection/models/riverChain.d.ts +30 -0
- package/dist/sync-agent/river-connection/models/riverChain.d.ts.map +1 -0
- package/dist/sync-agent/river-connection/models/riverChain.js +93 -0
- package/dist/sync-agent/river-connection/models/riverChain.js.map +1 -0
- package/dist/sync-agent/river-connection/models/transactionalClient.d.ts +11 -0
- package/dist/sync-agent/river-connection/models/transactionalClient.d.ts.map +1 -0
- package/dist/sync-agent/river-connection/models/transactionalClient.js +14 -0
- package/dist/sync-agent/river-connection/models/transactionalClient.js.map +1 -0
- package/dist/sync-agent/river-connection/riverConnection.d.ts +61 -0
- package/dist/sync-agent/river-connection/riverConnection.d.ts.map +1 -0
- package/dist/sync-agent/river-connection/riverConnection.js +229 -0
- package/dist/sync-agent/river-connection/riverConnection.js.map +1 -0
- package/dist/sync-agent/spaces/models/channel.d.ts +84 -0
- package/dist/sync-agent/spaces/models/channel.d.ts.map +1 -0
- package/dist/sync-agent/spaces/models/channel.js +173 -0
- package/dist/sync-agent/spaces/models/channel.js.map +1 -0
- package/dist/sync-agent/spaces/models/space.d.ts +57 -0
- package/dist/sync-agent/spaces/models/space.d.ts.map +1 -0
- package/dist/sync-agent/spaces/models/space.js +147 -0
- package/dist/sync-agent/spaces/models/space.js.map +1 -0
- package/dist/sync-agent/spaces/spaces.d.ts +29 -0
- package/dist/sync-agent/spaces/spaces.d.ts.map +1 -0
- package/dist/sync-agent/spaces/spaces.js +90 -0
- package/dist/sync-agent/spaces/spaces.js.map +1 -0
- package/dist/sync-agent/syncAgent.d.ts +68 -0
- package/dist/sync-agent/syncAgent.d.ts.map +1 -0
- package/dist/sync-agent/syncAgent.js +108 -0
- package/dist/sync-agent/syncAgent.js.map +1 -0
- package/dist/sync-agent/timeline/models/pendingReplacedEvents.d.ts +12 -0
- package/dist/sync-agent/timeline/models/pendingReplacedEvents.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/pendingReplacedEvents.js +20 -0
- package/dist/sync-agent/timeline/models/pendingReplacedEvents.js.map +1 -0
- package/dist/sync-agent/timeline/models/reactions.d.ts +13 -0
- package/dist/sync-agent/timeline/models/reactions.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/reactions.js +67 -0
- package/dist/sync-agent/timeline/models/reactions.js.map +1 -0
- package/dist/sync-agent/timeline/models/replacedEvents.d.ts +18 -0
- package/dist/sync-agent/timeline/models/replacedEvents.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/replacedEvents.js +19 -0
- package/dist/sync-agent/timeline/models/replacedEvents.js.map +1 -0
- package/dist/sync-agent/timeline/models/threadStats.d.ts +13 -0
- package/dist/sync-agent/timeline/models/threadStats.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/threadStats.js +99 -0
- package/dist/sync-agent/timeline/models/threadStats.js.map +1 -0
- package/dist/sync-agent/timeline/models/threads.d.ts +14 -0
- package/dist/sync-agent/timeline/models/threads.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/threads.js +57 -0
- package/dist/sync-agent/timeline/models/threads.js.map +1 -0
- package/dist/sync-agent/timeline/models/timeline-types.d.ts +364 -0
- package/dist/sync-agent/timeline/models/timeline-types.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/timeline-types.js +66 -0
- package/dist/sync-agent/timeline/models/timeline-types.js.map +1 -0
- package/dist/sync-agent/timeline/models/timelineEvent.d.ts +14 -0
- package/dist/sync-agent/timeline/models/timelineEvent.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/timelineEvent.js +1080 -0
- package/dist/sync-agent/timeline/models/timelineEvent.js.map +1 -0
- package/dist/sync-agent/timeline/models/timelineEvents.d.ts +13 -0
- package/dist/sync-agent/timeline/models/timelineEvents.d.ts.map +1 -0
- package/dist/sync-agent/timeline/models/timelineEvents.js +37 -0
- package/dist/sync-agent/timeline/models/timelineEvents.js.map +1 -0
- package/dist/sync-agent/timeline/timeline.d.ts +43 -0
- package/dist/sync-agent/timeline/timeline.d.ts.map +1 -0
- package/dist/sync-agent/timeline/timeline.js +246 -0
- package/dist/sync-agent/timeline/timeline.js.map +1 -0
- package/dist/sync-agent/user/models/userInbox.d.ts +21 -0
- package/dist/sync-agent/user/models/userInbox.d.ts.map +1 -0
- package/dist/sync-agent/user/models/userInbox.js +68 -0
- package/dist/sync-agent/user/models/userInbox.js.map +1 -0
- package/dist/sync-agent/user/models/userMemberships.d.ts +29 -0
- package/dist/sync-agent/user/models/userMemberships.d.ts.map +1 -0
- package/dist/sync-agent/user/models/userMemberships.js +84 -0
- package/dist/sync-agent/user/models/userMemberships.js.map +1 -0
- package/dist/sync-agent/user/models/userMetadata.d.ts +21 -0
- package/dist/sync-agent/user/models/userMetadata.d.ts.map +1 -0
- package/dist/sync-agent/user/models/userMetadata.js +68 -0
- package/dist/sync-agent/user/models/userMetadata.js.map +1 -0
- package/dist/sync-agent/user/models/userSettings.d.ts +17 -0
- package/dist/sync-agent/user/models/userSettings.d.ts.map +1 -0
- package/dist/sync-agent/user/models/userSettings.js +48 -0
- package/dist/sync-agent/user/models/userSettings.js.map +1 -0
- package/dist/sync-agent/user/user.d.ts +18 -0
- package/dist/sync-agent/user/user.d.ts.map +1 -0
- package/dist/sync-agent/user/user.js +30 -0
- package/dist/sync-agent/user/user.js.map +1 -0
- package/dist/sync-agent/utils/bot.d.ts +16 -0
- package/dist/sync-agent/utils/bot.d.ts.map +1 -0
- package/dist/sync-agent/utils/bot.js +39 -0
- package/dist/sync-agent/utils/bot.js.map +1 -0
- package/dist/sync-agent/utils/promiseQueue.d.ts +6 -0
- package/dist/sync-agent/utils/promiseQueue.d.ts.map +1 -0
- package/dist/sync-agent/utils/promiseQueue.js +20 -0
- package/dist/sync-agent/utils/promiseQueue.js.map +1 -0
- package/dist/sync-agent/utils/providers.d.ts +5 -0
- package/dist/sync-agent/utils/providers.d.ts.map +1 -0
- package/dist/sync-agent/utils/providers.js +16 -0
- package/dist/sync-agent/utils/providers.js.map +1 -0
- package/dist/sync-agent/utils/spaceUtils.d.ts +22 -0
- package/dist/sync-agent/utils/spaceUtils.d.ts.map +1 -0
- package/dist/sync-agent/utils/spaceUtils.js +27 -0
- package/dist/sync-agent/utils/spaceUtils.js.map +1 -0
- package/dist/syncEvents.d.ts +9 -0
- package/dist/syncEvents.d.ts.map +1 -0
- package/dist/syncEvents.js +2 -0
- package/dist/syncEvents.js.map +1 -0
- package/dist/syncedStream.d.ts +22 -0
- package/dist/syncedStream.d.ts.map +1 -0
- package/dist/syncedStream.js +108 -0
- package/dist/syncedStream.js.map +1 -0
- package/dist/syncedStreams.d.ts +46 -0
- package/dist/syncedStreams.d.ts.map +1 -0
- package/dist/syncedStreams.js +116 -0
- package/dist/syncedStreams.js.map +1 -0
- package/dist/syncedStreamsExtension.d.ts +50 -0
- package/dist/syncedStreamsExtension.d.ts.map +1 -0
- package/dist/syncedStreamsExtension.js +285 -0
- package/dist/syncedStreamsExtension.js.map +1 -0
- package/dist/syncedStreamsLoop.d.ts +121 -0
- package/dist/syncedStreamsLoop.d.ts.map +1 -0
- package/dist/syncedStreamsLoop.js +781 -0
- package/dist/syncedStreamsLoop.js.map +1 -0
- package/dist/tags.d.ts +7 -0
- package/dist/tags.d.ts.map +1 -0
- package/dist/tags.js +144 -0
- package/dist/tags.js.map +1 -0
- package/dist/tests/bob_testUtils.d.ts +4 -0
- package/dist/tests/bob_testUtils.d.ts.map +1 -0
- package/dist/tests/bob_testUtils.js +159 -0
- package/dist/tests/bob_testUtils.js.map +1 -0
- package/dist/tests/multi/channelScrubbing.test.d.ts +5 -0
- package/dist/tests/multi/channelScrubbing.test.d.ts.map +1 -0
- package/dist/tests/multi/channelScrubbing.test.js +33 -0
- package/dist/tests/multi/channelScrubbing.test.js.map +1 -0
- package/dist/tests/multi/channelSpaceSettings.test.d.ts +5 -0
- package/dist/tests/multi/channelSpaceSettings.test.d.ts.map +1 -0
- package/dist/tests/multi/channelSpaceSettings.test.js +206 -0
- package/dist/tests/multi/channelSpaceSettings.test.js.map +1 -0
- package/dist/tests/multi/disableChannel.test.d.ts +5 -0
- package/dist/tests/multi/disableChannel.test.d.ts.map +1 -0
- package/dist/tests/multi/disableChannel.test.js +30 -0
- package/dist/tests/multi/disableChannel.test.js.map +1 -0
- package/dist/tests/multi/disableSpace.test.d.ts +5 -0
- package/dist/tests/multi/disableSpace.test.d.ts.map +1 -0
- package/dist/tests/multi/disableSpace.test.js +37 -0
- package/dist/tests/multi/disableSpace.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.js +129 -0
- package/dist/tests/multi/entitlements/channelEntitlementPermissions.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.js +44 -0
- package/dist/tests/multi/entitlements/channelWithThreeNestedEntitlement.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.js +145 -0
- package/dist/tests/multi/entitlements/channelsWithComplexEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.js +72 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlementLoss.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlements.test.js +51 -0
- package/dist/tests/multi/entitlements/channelsWithEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.js +86 -0
- package/dist/tests/multi/entitlements/channelsWithErc20Entitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.js +69 -0
- package/dist/tests/multi/entitlements/channelsWithErc721Entitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.js +145 -0
- package/dist/tests/multi/entitlements/channelsWithEthBalanceEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.js +53 -0
- package/dist/tests/multi/entitlements/channelsWithUserEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.js +151 -0
- package/dist/tests/multi/entitlements/spaceWithComplexEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithEntitlements.test.js +101 -0
- package/dist/tests/multi/entitlements/spaceWithEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.js +103 -0
- package/dist/tests/multi/entitlements/spaceWithErc20Entitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.js +84 -0
- package/dist/tests/multi/entitlements/spaceWithErc721Entitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.js +168 -0
- package/dist/tests/multi/entitlements/spaceWithEthBalanceEntitlements.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.js +45 -0
- package/dist/tests/multi/entitlements/spaceWithThreeNestedEntitlement.test.js.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.js +79 -0
- package/dist/tests/multi/entitlements/spaceWithUserEntitlements.test.js.map +1 -0
- package/dist/tests/multi/legacySpace.test.d.ts +5 -0
- package/dist/tests/multi/legacySpace.test.d.ts.map +1 -0
- package/dist/tests/multi/legacySpace.test.js +48 -0
- package/dist/tests/multi/legacySpace.test.js.map +1 -0
- package/dist/tests/multi/mediaWithEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/mediaWithEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/mediaWithEntitlements.test.js +152 -0
- package/dist/tests/multi/mediaWithEntitlements.test.js.map +1 -0
- package/dist/tests/multi/membershipManagement.test.d.ts +5 -0
- package/dist/tests/multi/membershipManagement.test.d.ts.map +1 -0
- package/dist/tests/multi/membershipManagement.test.js +76 -0
- package/dist/tests/multi/membershipManagement.test.js.map +1 -0
- package/dist/tests/multi/notificationService.test.d.ts +2 -0
- package/dist/tests/multi/notificationService.test.d.ts.map +1 -0
- package/dist/tests/multi/notificationService.test.js +51 -0
- package/dist/tests/multi/notificationService.test.js.map +1 -0
- package/dist/tests/multi/riverAirdropDapp.test.d.ts +5 -0
- package/dist/tests/multi/riverAirdropDapp.test.d.ts.map +1 -0
- package/dist/tests/multi/riverAirdropDapp.test.js +43 -0
- package/dist/tests/multi/riverAirdropDapp.test.js.map +1 -0
- package/dist/tests/multi/spaceDapp.test.d.ts +5 -0
- package/dist/tests/multi/spaceDapp.test.d.ts.map +1 -0
- package/dist/tests/multi/spaceDapp.test.js +59 -0
- package/dist/tests/multi/spaceDapp.test.js.map +1 -0
- package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.d.ts +2 -0
- package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.d.ts.map +1 -0
- package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.js +61 -0
- package/dist/tests/multi/spaceWithVariousPriceConfigurations.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/member-queue.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/member-queue.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/member-queue.test.js +46 -0
- package/dist/tests/multi/sync-agent/member-queue.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/member.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/member.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/member.test.js +45 -0
- package/dist/tests/multi/sync-agent/member.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/members.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/members.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/members.test.js +35 -0
- package/dist/tests/multi/sync-agent/members.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/riverConnection.test.d.ts +5 -0
- package/dist/tests/multi/sync-agent/riverConnection.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/riverConnection.test.js +49 -0
- package/dist/tests/multi/sync-agent/riverConnection.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/spaces.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/spaces.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/spaces.test.js +33 -0
- package/dist/tests/multi/sync-agent/spaces.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/streams.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/streams.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/streams.test.js +27 -0
- package/dist/tests/multi/sync-agent/streams.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/syncAgent.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/syncAgent.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/syncAgent.test.js +65 -0
- package/dist/tests/multi/sync-agent/syncAgent.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/syncAgents.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/syncAgents.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/syncAgents.test.js +160 -0
- package/dist/tests/multi/sync-agent/syncAgents.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/timeline.test.d.ts +2 -0
- package/dist/tests/multi/sync-agent/timeline.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/timeline.test.js +220 -0
- package/dist/tests/multi/sync-agent/timeline.test.js.map +1 -0
- package/dist/tests/multi/sync-agent/user.test.d.ts +5 -0
- package/dist/tests/multi/sync-agent/user.test.d.ts.map +1 -0
- package/dist/tests/multi/sync-agent/user.test.js +55 -0
- package/dist/tests/multi/sync-agent/user.test.js.map +1 -0
- package/dist/tests/multi/transactions.test.d.ts +5 -0
- package/dist/tests/multi/transactions.test.d.ts.map +1 -0
- package/dist/tests/multi/transactions.test.js +153 -0
- package/dist/tests/multi/transactions.test.js.map +1 -0
- package/dist/tests/multi/transactions_SpaceReview.test.d.ts +2 -0
- package/dist/tests/multi/transactions_SpaceReview.test.d.ts.map +1 -0
- package/dist/tests/multi/transactions_SpaceReview.test.js +280 -0
- package/dist/tests/multi/transactions_SpaceReview.test.js.map +1 -0
- package/dist/tests/multi/transactions_Tip.test.d.ts +5 -0
- package/dist/tests/multi/transactions_Tip.test.d.ts.map +1 -0
- package/dist/tests/multi/transactions_Tip.test.js +235 -0
- package/dist/tests/multi/transactions_Tip.test.js.map +1 -0
- package/dist/tests/multi/withEntitlements.test.d.ts +5 -0
- package/dist/tests/multi/withEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi/withEntitlements.test.js +125 -0
- package/dist/tests/multi/withEntitlements.test.js.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriends.test.d.ts +5 -0
- package/dist/tests/multi_ne/aliceAndFriends.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriends.test.js +20 -0
- package/dist/tests/multi_ne/aliceAndFriends.test.js.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriends10for10.test.d.ts +5 -0
- package/dist/tests/multi_ne/aliceAndFriends10for10.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriends10for10.test.js +23 -0
- package/dist/tests/multi_ne/aliceAndFriends10for10.test.js.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriends3for8.test.d.ts +5 -0
- package/dist/tests/multi_ne/aliceAndFriends3for8.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriends3for8.test.js +22 -0
- package/dist/tests/multi_ne/aliceAndFriends3for8.test.js.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.d.ts +5 -0
- package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.js +28 -0
- package/dist/tests/multi_ne/aliceAndFriendslongAndRandom.test.js.map +1 -0
- package/dist/tests/multi_ne/bobFlushes.test.d.ts +5 -0
- package/dist/tests/multi_ne/bobFlushes.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/bobFlushes.test.js +20 -0
- package/dist/tests/multi_ne/bobFlushes.test.js.map +1 -0
- package/dist/tests/multi_ne/channels.test.d.ts +5 -0
- package/dist/tests/multi_ne/channels.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/channels.test.js +47 -0
- package/dist/tests/multi_ne/channels.test.js.map +1 -0
- package/dist/tests/multi_ne/client.test.d.ts +5 -0
- package/dist/tests/multi_ne/client.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/client.test.js +786 -0
- package/dist/tests/multi_ne/client.test.js.map +1 -0
- package/dist/tests/multi_ne/clientCrypto.test.d.ts +5 -0
- package/dist/tests/multi_ne/clientCrypto.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/clientCrypto.test.js +64 -0
- package/dist/tests/multi_ne/clientCrypto.test.js.map +1 -0
- package/dist/tests/multi_ne/clientDecryptionExtensions.test.d.ts +5 -0
- package/dist/tests/multi_ne/clientDecryptionExtensions.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/clientDecryptionExtensions.test.js +174 -0
- package/dist/tests/multi_ne/clientDecryptionExtensions.test.js.map +1 -0
- package/dist/tests/multi_ne/deviceKeyMessage.test.d.ts +5 -0
- package/dist/tests/multi_ne/deviceKeyMessage.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/deviceKeyMessage.test.js +154 -0
- package/dist/tests/multi_ne/deviceKeyMessage.test.js.map +1 -0
- package/dist/tests/multi_ne/dms.test.d.ts +5 -0
- package/dist/tests/multi_ne/dms.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/dms.test.js +131 -0
- package/dist/tests/multi_ne/dms.test.js.map +1 -0
- package/dist/tests/multi_ne/gdms.test.d.ts +5 -0
- package/dist/tests/multi_ne/gdms.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/gdms.test.js +274 -0
- package/dist/tests/multi_ne/gdms.test.js.map +1 -0
- package/dist/tests/multi_ne/id.test.d.ts +5 -0
- package/dist/tests/multi_ne/id.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/id.test.js +70 -0
- package/dist/tests/multi_ne/id.test.js.map +1 -0
- package/dist/tests/multi_ne/makeStreamRpcClient.test.d.ts +5 -0
- package/dist/tests/multi_ne/makeStreamRpcClient.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/makeStreamRpcClient.test.js +77 -0
- package/dist/tests/multi_ne/makeStreamRpcClient.test.js.map +1 -0
- package/dist/tests/multi_ne/media.test.d.ts +5 -0
- package/dist/tests/multi_ne/media.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/media.test.js +218 -0
- package/dist/tests/multi_ne/media.test.js.map +1 -0
- package/dist/tests/multi_ne/memberMetadata.test.d.ts +5 -0
- package/dist/tests/multi_ne/memberMetadata.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/memberMetadata.test.js +545 -0
- package/dist/tests/multi_ne/memberMetadata.test.js.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.d.ts +5 -0
- package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.js +54 -0
- package/dist/tests/multi_ne/memberMetadata_DisplayNames.test.js.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.d.ts +5 -0
- package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.js +37 -0
- package/dist/tests/multi_ne/memberMetadata_EnsAddresses.test.js.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_Nft.test.d.ts +5 -0
- package/dist/tests/multi_ne/memberMetadata_Nft.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_Nft.test.js +49 -0
- package/dist/tests/multi_ne/memberMetadata_Nft.test.js.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_Usernames.test.d.ts +5 -0
- package/dist/tests/multi_ne/memberMetadata_Usernames.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/memberMetadata_Usernames.test.js +113 -0
- package/dist/tests/multi_ne/memberMetadata_Usernames.test.js.map +1 -0
- package/dist/tests/multi_ne/nodeSelection.test.d.ts +5 -0
- package/dist/tests/multi_ne/nodeSelection.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/nodeSelection.test.js +41 -0
- package/dist/tests/multi_ne/nodeSelection.test.js.map +1 -0
- package/dist/tests/multi_ne/outboundGroupSession.test.d.ts +5 -0
- package/dist/tests/multi_ne/outboundGroupSession.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/outboundGroupSession.test.js +107 -0
- package/dist/tests/multi_ne/outboundGroupSession.test.js.map +1 -0
- package/dist/tests/multi_ne/persistenceStore.test.d.ts +5 -0
- package/dist/tests/multi_ne/persistenceStore.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/persistenceStore.test.js +27 -0
- package/dist/tests/multi_ne/persistenceStore.test.js.map +1 -0
- package/dist/tests/multi_ne/restart.test.d.ts +4 -0
- package/dist/tests/multi_ne/restart.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/restart.test.js +161 -0
- package/dist/tests/multi_ne/restart.test.js.map +1 -0
- package/dist/tests/multi_ne/sign.test.d.ts +5 -0
- package/dist/tests/multi_ne/sign.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/sign.test.js +218 -0
- package/dist/tests/multi_ne/sign.test.js.map +1 -0
- package/dist/tests/multi_ne/space.test.d.ts +5 -0
- package/dist/tests/multi_ne/space.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/space.test.js +190 -0
- package/dist/tests/multi_ne/space.test.js.map +1 -0
- package/dist/tests/multi_ne/streamMembershipHardening.test.d.ts +5 -0
- package/dist/tests/multi_ne/streamMembershipHardening.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/streamMembershipHardening.test.js +30 -0
- package/dist/tests/multi_ne/streamMembershipHardening.test.js.map +1 -0
- package/dist/tests/multi_ne/streamRpcClient.test.d.ts +5 -0
- package/dist/tests/multi_ne/streamRpcClient.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/streamRpcClient.test.js +559 -0
- package/dist/tests/multi_ne/streamRpcClient.test.js.map +1 -0
- package/dist/tests/multi_ne/streamRpcClientGetSince.test.d.ts +2 -0
- package/dist/tests/multi_ne/streamRpcClientGetSince.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/streamRpcClientGetSince.test.js +105 -0
- package/dist/tests/multi_ne/streamRpcClientGetSince.test.js.map +1 -0
- package/dist/tests/multi_ne/streamRpcClientSync.test.d.ts +5 -0
- package/dist/tests/multi_ne/streamRpcClientSync.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/streamRpcClientSync.test.js +199 -0
- package/dist/tests/multi_ne/streamRpcClientSync.test.js.map +1 -0
- package/dist/tests/multi_ne/streamStateView_User.test.d.ts +5 -0
- package/dist/tests/multi_ne/streamStateView_User.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/streamStateView_User.test.js +31 -0
- package/dist/tests/multi_ne/streamStateView_User.test.js.map +1 -0
- package/dist/tests/multi_ne/syncWithBlocks.test.d.ts +2 -0
- package/dist/tests/multi_ne/syncWithBlocks.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/syncWithBlocks.test.js +155 -0
- package/dist/tests/multi_ne/syncWithBlocks.test.js.map +1 -0
- package/dist/tests/multi_ne/syncedStream.test.d.ts +5 -0
- package/dist/tests/multi_ne/syncedStream.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/syncedStream.test.js +62 -0
- package/dist/tests/multi_ne/syncedStream.test.js.map +1 -0
- package/dist/tests/multi_ne/syncedStreams.test.d.ts +5 -0
- package/dist/tests/multi_ne/syncedStreams.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/syncedStreams.test.js +504 -0
- package/dist/tests/multi_ne/syncedStreams.test.js.map +1 -0
- package/dist/tests/multi_ne/tags.test.d.ts +2 -0
- package/dist/tests/multi_ne/tags.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/tags.test.js +186 -0
- package/dist/tests/multi_ne/tags.test.js.map +1 -0
- package/dist/tests/multi_ne/trading.solana.test.d.ts +2 -0
- package/dist/tests/multi_ne/trading.solana.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/trading.solana.test.js +229 -0
- package/dist/tests/multi_ne/trading.solana.test.js.map +1 -0
- package/dist/tests/multi_ne/trading.test.d.ts +2 -0
- package/dist/tests/multi_ne/trading.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/trading.test.js +243 -0
- package/dist/tests/multi_ne/trading.test.js.map +1 -0
- package/dist/tests/multi_ne/userInboxMessage.test.d.ts +5 -0
- package/dist/tests/multi_ne/userInboxMessage.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/userInboxMessage.test.js +56 -0
- package/dist/tests/multi_ne/userInboxMessage.test.js.map +1 -0
- package/dist/tests/multi_ne/userSettings.test.d.ts +5 -0
- package/dist/tests/multi_ne/userSettings.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/userSettings.test.js +116 -0
- package/dist/tests/multi_ne/userSettings.test.js.map +1 -0
- package/dist/tests/multi_ne/workflows.test.d.ts +5 -0
- package/dist/tests/multi_ne/workflows.test.d.ts.map +1 -0
- package/dist/tests/multi_ne/workflows.test.js +88 -0
- package/dist/tests/multi_ne/workflows.test.js.map +1 -0
- package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.d.ts +6 -0
- package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.js +78 -0
- package/dist/tests/multi_v2/entitlements/channelsWithCrossChainEntitlements.test.js.map +1 -0
- package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.d.ts +6 -0
- package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.d.ts.map +1 -0
- package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.js +89 -0
- package/dist/tests/multi_v2/entitlements/channelsWithErc1155Entitlement.test.js.map +1 -0
- package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.d.ts +6 -0
- package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.d.ts.map +1 -0
- package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.js +88 -0
- package/dist/tests/multi_v2/entitlements/spaceWithCrossChainEntitlements.test.js.map +1 -0
- package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.d.ts +6 -0
- package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.d.ts.map +1 -0
- package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.js +105 -0
- package/dist/tests/multi_v2/entitlements/spaceWithErc1155Entitlements.test.js.map +1 -0
- package/dist/tests/multi_v2/updateRole.test.d.ts +5 -0
- package/dist/tests/multi_v2/updateRole.test.d.ts.map +1 -0
- package/dist/tests/multi_v2/updateRole.test.js +25 -0
- package/dist/tests/multi_v2/updateRole.test.js.map +1 -0
- package/dist/tests/syncAgent_testUtils.d.ts +10 -0
- package/dist/tests/syncAgent_testUtils.d.ts.map +1 -0
- package/dist/tests/syncAgent_testUtils.js +41 -0
- package/dist/tests/syncAgent_testUtils.js.map +1 -0
- package/dist/tests/testDriver_testUtils.d.ts +2 -0
- package/dist/tests/testDriver_testUtils.d.ts.map +1 -0
- package/dist/tests/testDriver_testUtils.js +157 -0
- package/dist/tests/testDriver_testUtils.js.map +1 -0
- package/dist/tests/testUtils.d.ts +188 -0
- package/dist/tests/testUtils.d.ts.map +1 -0
- package/dist/tests/testUtils.js +1026 -0
- package/dist/tests/testUtils.js.map +1 -0
- package/dist/tests/unit/crypto.test.d.ts +5 -0
- package/dist/tests/unit/crypto.test.d.ts.map +1 -0
- package/dist/tests/unit/crypto.test.js +109 -0
- package/dist/tests/unit/crypto.test.js.map +1 -0
- package/dist/tests/unit/crypto_utils.test.d.ts +5 -0
- package/dist/tests/unit/crypto_utils.test.d.ts.map +1 -0
- package/dist/tests/unit/crypto_utils.test.js +35 -0
- package/dist/tests/unit/crypto_utils.test.js.map +1 -0
- package/dist/tests/unit/decorators.test.d.ts +2 -0
- package/dist/tests/unit/decorators.test.d.ts.map +1 -0
- package/dist/tests/unit/decorators.test.js +76 -0
- package/dist/tests/unit/decorators.test.js.map +1 -0
- package/dist/tests/unit/snapshotMigration0000.test.d.ts +2 -0
- package/dist/tests/unit/snapshotMigration0000.test.d.ts.map +1 -0
- package/dist/tests/unit/snapshotMigration0000.test.js +12 -0
- package/dist/tests/unit/snapshotMigration0000.test.js.map +1 -0
- package/dist/tests/unit/snapshotMigration0001.test.d.ts +2 -0
- package/dist/tests/unit/snapshotMigration0001.test.d.ts.map +1 -0
- package/dist/tests/unit/snapshotMigration0001.test.js +63 -0
- package/dist/tests/unit/snapshotMigration0001.test.js.map +1 -0
- package/dist/tests/unit/snapshotMigration0002.test.d.ts +2 -0
- package/dist/tests/unit/snapshotMigration0002.test.d.ts.map +1 -0
- package/dist/tests/unit/snapshotMigration0002.test.js +31 -0
- package/dist/tests/unit/snapshotMigration0002.test.js.map +1 -0
- package/dist/tests/unit/store.test.d.ts +2 -0
- package/dist/tests/unit/store.test.d.ts.map +1 -0
- package/dist/tests/unit/store.test.js +47 -0
- package/dist/tests/unit/store.test.js.map +1 -0
- package/dist/tests/unit/testUtils.test.d.ts +5 -0
- package/dist/tests/unit/testUtils.test.d.ts.map +1 -0
- package/dist/tests/unit/testUtils.test.js +65 -0
- package/dist/tests/unit/testUtils.test.js.map +1 -0
- package/dist/types.d.ts +168 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +659 -0
- package/dist/types.js.map +1 -0
- package/dist/unauthenticatedClient.d.ts +26 -0
- package/dist/unauthenticatedClient.d.ts.map +1 -0
- package/dist/unauthenticatedClient.js +156 -0
- package/dist/unauthenticatedClient.js.map +1 -0
- package/dist/utils.d.ts +28 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +99 -0
- package/dist/utils.js.map +1 -0
- 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
|