Page MenuHomePhorge

D14641.1768403996.diff
No OneTemporary

Size
70 KB
Referenced Files
None
Subscribers
None

D14641.1768403996.diff

diff --git a/lib/shared/threads/community-announcement-root-spec.js b/lib/shared/threads/community-announcement-root-spec.js
--- a/lib/shared/threads/community-announcement-root-spec.js
+++ b/lib/shared/threads/community-announcement-root-spec.js
@@ -2,11 +2,13 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const communityAnnouncementRootSpec: ThreadSpec = Object.freeze({
- traits: new Set(['community', 'announcement']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Community',
-});
+const communityAnnouncementRootSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['community', 'announcement']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Community',
+ });
export { communityAnnouncementRootSpec };
diff --git a/lib/shared/threads/community-open-announcement-subthread-spec.js b/lib/shared/threads/community-open-announcement-subthread-spec.js
--- a/lib/shared/threads/community-open-announcement-subthread-spec.js
+++ b/lib/shared/threads/community-open-announcement-subthread-spec.js
@@ -2,11 +2,13 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const communityOpenAnnouncementSubthreadSpec: ThreadSpec = Object.freeze({
- traits: new Set(['communitySubthread', 'announcement']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Open',
-});
+const communityOpenAnnouncementSubthreadSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['communitySubthread', 'announcement']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Open',
+ });
export { communityOpenAnnouncementSubthreadSpec };
diff --git a/lib/shared/threads/community-open-subthread-spec.js b/lib/shared/threads/community-open-subthread-spec.js
--- a/lib/shared/threads/community-open-subthread-spec.js
+++ b/lib/shared/threads/community-open-subthread-spec.js
@@ -2,11 +2,13 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const communityOpenSubthreadSpec: ThreadSpec = Object.freeze({
- traits: new Set(['communitySubthread']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Open',
-});
+const communityOpenSubthreadSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['communitySubthread']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Open',
+ });
export { communityOpenSubthreadSpec };
diff --git a/lib/shared/threads/community-root-spec.js b/lib/shared/threads/community-root-spec.js
--- a/lib/shared/threads/community-root-spec.js
+++ b/lib/shared/threads/community-root-spec.js
@@ -2,8 +2,9 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const communityRootSpec: ThreadSpec = Object.freeze({
+const communityRootSpec: ThreadSpec<MemberInfoSansPermissions> = Object.freeze({
traits: new Set(['community']),
protocol: keyserverThreadProtocol,
threadLabel: 'Community',
diff --git a/lib/shared/threads/community-secret-announcement-subthread-spec.js b/lib/shared/threads/community-secret-announcement-subthread-spec.js
--- a/lib/shared/threads/community-secret-announcement-subthread-spec.js
+++ b/lib/shared/threads/community-secret-announcement-subthread-spec.js
@@ -2,11 +2,13 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const communitySecretAnnouncementSubthreadSpec: ThreadSpec = Object.freeze({
- traits: new Set(['communitySubthread', 'announcement']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Secret',
-});
+const communitySecretAnnouncementSubthreadSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['communitySubthread', 'announcement']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Secret',
+ });
export { communitySecretAnnouncementSubthreadSpec };
diff --git a/lib/shared/threads/community-secret-subthread-spec.js b/lib/shared/threads/community-secret-subthread-spec.js
--- a/lib/shared/threads/community-secret-subthread-spec.js
+++ b/lib/shared/threads/community-secret-subthread-spec.js
@@ -2,11 +2,13 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const communitySecretSubthreadSpec: ThreadSpec = Object.freeze({
- traits: new Set(['communitySubthread']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Secret',
-});
+const communitySecretSubthreadSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['communitySubthread']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Secret',
+ });
export { communitySecretSubthreadSpec };
diff --git a/lib/shared/threads/genesis-personal-spec.js b/lib/shared/threads/genesis-personal-spec.js
--- a/lib/shared/threads/genesis-personal-spec.js
+++ b/lib/shared/threads/genesis-personal-spec.js
@@ -2,11 +2,13 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const genesisPersonalSpec: ThreadSpec = Object.freeze({
- traits: new Set(['personal']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Personal',
-});
+const genesisPersonalSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['personal']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Personal',
+ });
export { genesisPersonalSpec };
diff --git a/lib/shared/threads/genesis-private-spec.js b/lib/shared/threads/genesis-private-spec.js
--- a/lib/shared/threads/genesis-private-spec.js
+++ b/lib/shared/threads/genesis-private-spec.js
@@ -2,11 +2,14 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const genesisPrivateSpec: ThreadSpec = Object.freeze({
- traits: new Set(['private']),
- protocol: keyserverThreadProtocol,
- threadLabel: 'Private',
-});
+const genesisPrivateSpec: ThreadSpec<MemberInfoSansPermissions> = Object.freeze(
+ {
+ traits: new Set(['private']),
+ protocol: keyserverThreadProtocol,
+ threadLabel: 'Private',
+ },
+);
export { genesisPrivateSpec };
diff --git a/lib/shared/threads/genesis-spec.js b/lib/shared/threads/genesis-spec.js
--- a/lib/shared/threads/genesis-spec.js
+++ b/lib/shared/threads/genesis-spec.js
@@ -2,8 +2,9 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const genesisSpec: ThreadSpec = Object.freeze({
+const genesisSpec: ThreadSpec<MemberInfoSansPermissions> = Object.freeze({
traits: new Set(['community', 'announcement']),
protocol: keyserverThreadProtocol,
threadLabel: 'Community',
diff --git a/lib/shared/threads/local-spec.js b/lib/shared/threads/local-spec.js
--- a/lib/shared/threads/local-spec.js
+++ b/lib/shared/threads/local-spec.js
@@ -2,8 +2,9 @@
import { dmThreadProtocol } from './protocols/dm-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MinimallyEncodedThickMemberInfo } from '../../types/minimally-encoded-thread-permissions-types.js';
-const localSpec: ThreadSpec = Object.freeze({
+const localSpec: ThreadSpec<MinimallyEncodedThickMemberInfo> = Object.freeze({
traits: new Set(),
protocol: dmThreadProtocol,
threadLabel: 'Local DM',
diff --git a/lib/shared/threads/personal-spec.js b/lib/shared/threads/personal-spec.js
--- a/lib/shared/threads/personal-spec.js
+++ b/lib/shared/threads/personal-spec.js
@@ -2,11 +2,14 @@
import { dmThreadProtocol } from './protocols/dm-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MinimallyEncodedThickMemberInfo } from '../../types/minimally-encoded-thread-permissions-types.js';
-const personalSpec: ThreadSpec = Object.freeze({
- traits: new Set(['personal']),
- protocol: dmThreadProtocol,
- threadLabel: 'Local DM',
-});
+const personalSpec: ThreadSpec<MinimallyEncodedThickMemberInfo> = Object.freeze(
+ {
+ traits: new Set(['personal']),
+ protocol: dmThreadProtocol,
+ threadLabel: 'Local DM',
+ },
+);
export { personalSpec };
diff --git a/lib/shared/threads/private-spec.js b/lib/shared/threads/private-spec.js
--- a/lib/shared/threads/private-spec.js
+++ b/lib/shared/threads/private-spec.js
@@ -2,8 +2,9 @@
import { dmThreadProtocol } from './protocols/dm-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MinimallyEncodedThickMemberInfo } from '../../types/minimally-encoded-thread-permissions-types.js';
-const privateSpec: ThreadSpec = Object.freeze({
+const privateSpec: ThreadSpec<MinimallyEncodedThickMemberInfo> = Object.freeze({
traits: new Set(['private']),
protocol: dmThreadProtocol,
threadLabel: 'Local DM',
diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js
--- a/lib/shared/threads/protocols/dm-thread-protocol.js
+++ b/lib/shared/threads/protocols/dm-thread-protocol.js
@@ -16,11 +16,27 @@
DMSendReactionMessageOperation,
DMThreadSettingsChanges,
} from '../../../types/dm-ops.js';
-import { thickThreadTypes } from '../../../types/thread-types-enum.js';
-import type { ChangeThreadSettingsPayload } from '../../../types/thread-types.js';
+import type {
+ RoleInfo,
+ ThreadCurrentUserInfo,
+ ThickRawThreadInfo,
+ MinimallyEncodedThickMemberInfo,
+} from '../../../types/minimally-encoded-thread-permissions-types.js';
+import {
+ assertThickThreadType,
+ thickThreadTypes,
+} from '../../../types/thread-types-enum.js';
+import type {
+ ChangeThreadSettingsPayload,
+ ClientDBThreadInfo,
+} from '../../../types/thread-types.js';
+import { threadTimestampsValidator } from '../../../types/thread-types.js';
import { dateString as stringFromDate } from '../../../utils/date-utils.js';
import { SendMessageError } from '../../../utils/errors.js';
-import { pendingThickSidebarURLPrefix } from '../../../utils/validation-utils.js';
+import {
+ assertWithValidator,
+ pendingThickSidebarURLPrefix,
+} from '../../../utils/validation-utils.js';
import {
dmOperationSpecificationTypes,
type OutboundDMOperationSpecification,
@@ -54,533 +70,598 @@
ProtocolLeaveThreadInput,
} from '../thread-spec.js';
-const dmThreadProtocol: ThreadProtocol = Object.freeze({
- sendTextMessage: async (
- message: ProtocolSendTextMessageInput,
- utils: SendTextMessageUtils,
- ) => {
- const { messageInfo, threadInfo, parentThreadInfo } = message;
- const { localID } = messageInfo;
- invariant(
- localID !== null && localID !== undefined,
- 'localID should be set',
- );
-
- const messageID = getIDFromLocalID(localID);
- const time = Date.now();
-
- const recipients =
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR && parentThreadInfo
- ? parentThreadInfo.members
- : threadInfo.members;
- const recipientsIDs = recipients.map(recipient => recipient.id);
-
- const result = await utils.sendComposableDMOperation({
- type: dmOperationSpecificationTypes.OUTBOUND,
- op: {
- type: 'send_text_message',
- threadID: threadInfo.id,
- creatorID: messageInfo.creatorID,
- time,
- messageID,
- text: messageInfo.text,
- },
- // We need to use a different mechanism than `all_thread_members`
- // because when creating a thread, the thread might not yet
- // be in the store.
- recipients: {
- type: 'some_users',
- userIDs: recipientsIDs,
- },
- sendOnly: true,
- composableMessageID: localID,
- });
-
- if (result.result === 'failure' && result.failedMessageIDs.length > 0) {
- const error = new SendMessageError(
- 'Failed to send message to all peers',
- localID,
- messageInfo.threadID,
+const dmThreadProtocol: ThreadProtocol<MinimallyEncodedThickMemberInfo> =
+ Object.freeze({
+ sendTextMessage: async (
+ message: ProtocolSendTextMessageInput,
+ utils: SendTextMessageUtils,
+ ) => {
+ const { messageInfo, threadInfo, parentThreadInfo } = message;
+ const { localID } = messageInfo;
+ invariant(
+ localID !== null && localID !== undefined,
+ 'localID should be set',
);
- error.failedOutboundP2PMessageIDs = result.failedMessageIDs;
- throw error;
- }
- return {
- localID,
- serverID: messageID,
- threadID: messageInfo.threadID,
- time,
- };
- },
-
- sendMultimediaMessage: async (
- message: ProtocolSendMultimediaMessageInput,
- utils: SendMultimediaMessageUtils,
- ) => {
- const { messageInfo, threadInfo } = message;
- const { localID } = messageInfo;
- invariant(
- localID !== null && localID !== undefined,
- 'localID should be set',
- );
-
- const messageID = getIDFromLocalID(localID);
- const time = Date.now();
-
- const result = await utils.sendComposableDMOperation({
- type: dmOperationSpecificationTypes.OUTBOUND,
- op: {
- type: 'send_multimedia_message',
- threadID: threadInfo.id,
- creatorID: messageInfo.creatorID,
- time: Date.now(),
- messageID,
- media: messageInfo.media,
- },
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- sendOnly: true,
- composableMessageID: localID,
- });
-
- if (result.result === 'failure' && result.failedMessageIDs.length > 0) {
- const error = new SendMessageError(
- 'Failed to send message to all peers',
- localID,
- messageInfo.threadID,
- );
- error.failedOutboundP2PMessageIDs = result.failedMessageIDs;
- throw error;
- }
- return {
- result: {
+
+ const messageID = getIDFromLocalID(localID);
+ const time = Date.now();
+
+ const recipients =
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR && parentThreadInfo
+ ? parentThreadInfo.members
+ : threadInfo.members;
+ const recipientsIDs = recipients.map(recipient => recipient.id);
+
+ const result = await utils.sendComposableDMOperation({
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op: {
+ type: 'send_text_message',
+ threadID: threadInfo.id,
+ creatorID: messageInfo.creatorID,
+ time,
+ messageID,
+ text: messageInfo.text,
+ },
+ // We need to use a different mechanism than `all_thread_members`
+ // because when creating a thread, the thread might not yet
+ // be in the store.
+ recipients: {
+ type: 'some_users',
+ userIDs: recipientsIDs,
+ },
+ sendOnly: true,
+ composableMessageID: localID,
+ });
+
+ if (result.result === 'failure' && result.failedMessageIDs.length > 0) {
+ const error = new SendMessageError(
+ 'Failed to send message to all peers',
+ localID,
+ messageInfo.threadID,
+ );
+ error.failedOutboundP2PMessageIDs = result.failedMessageIDs;
+ throw error;
+ }
+ return {
localID,
serverID: messageID,
threadID: messageInfo.threadID,
time,
- },
- };
- },
-
- editTextMessage: async (
- message: ProtocolEditTextMessageInput,
- utils: EditTextMessageUtils,
- ) => {
- const { viewerID, threadInfo, messageID, newText } = message;
- invariant(viewerID, 'viewerID should be set');
- const op: DMSendEditMessageOperation = {
- type: 'send_edit_message',
- threadID: threadInfo.id,
- creatorID: viewerID,
- time: Date.now(),
- messageID: uuid.v4(),
- targetMessageID: messageID,
- text: newText,
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
- await utils.processAndSendDMOperation(opSpecification);
- },
-
- changeThreadSettings: async (
- protocolInput: ProtocolChangeThreadSettingsInput,
- utils: ChangeThreadSettingsUtils,
- ) => {
- const { viewerID, input } = protocolInput;
- invariant(viewerID, 'viewerID should be set');
- invariant(
- !input.changes.newMemberIDs,
- "DM protocol doesn't support" +
- ' adding new members when changing thread settings',
- );
-
- const changes: { ...DMThreadSettingsChanges } = {};
- if (input.changes.name) {
- changes.name = input.changes.name;
- }
- if (input.changes.description) {
- changes.description = input.changes.description;
- }
- if (input.changes.color) {
- changes.color = input.changes.color;
- }
- if (input.changes.avatar && input.changes.avatar.type === 'emoji') {
- changes.avatar = {
- type: 'emoji',
- emoji: input.changes.avatar.emoji,
- color: input.changes.avatar.color,
};
- } else if (input.changes.avatar && input.changes.avatar.type === 'ens') {
- changes.avatar = { type: 'ens' };
- } else if (
- input.changes.avatar &&
- input.changes.avatar.type === 'non_keyserver_image'
- ) {
- changes.avatar = {
- type: 'encrypted_image',
- blobURI: input.changes.avatar.blobURI,
- thumbHash: input.changes.avatar.thumbHash,
- encryptionKey: input.changes.avatar.encryptionKey,
+ },
+
+ sendMultimediaMessage: async (
+ message: ProtocolSendMultimediaMessageInput,
+ utils: SendMultimediaMessageUtils,
+ ) => {
+ const { messageInfo, threadInfo } = message;
+ const { localID } = messageInfo;
+ invariant(
+ localID !== null && localID !== undefined,
+ 'localID should be set',
+ );
+
+ const messageID = getIDFromLocalID(localID);
+ const time = Date.now();
+
+ const result = await utils.sendComposableDMOperation({
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op: {
+ type: 'send_multimedia_message',
+ threadID: threadInfo.id,
+ creatorID: messageInfo.creatorID,
+ time: Date.now(),
+ messageID,
+ media: messageInfo.media,
+ },
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ sendOnly: true,
+ composableMessageID: localID,
+ });
+
+ if (result.result === 'failure' && result.failedMessageIDs.length > 0) {
+ const error = new SendMessageError(
+ 'Failed to send message to all peers',
+ localID,
+ messageInfo.threadID,
+ );
+ error.failedOutboundP2PMessageIDs = result.failedMessageIDs;
+ throw error;
+ }
+ return {
+ result: {
+ localID,
+ serverID: messageID,
+ threadID: messageInfo.threadID,
+ time,
+ },
+ };
+ },
+
+ editTextMessage: async (
+ message: ProtocolEditTextMessageInput,
+ utils: EditTextMessageUtils,
+ ) => {
+ const { viewerID, threadInfo, messageID, newText } = message;
+ invariant(viewerID, 'viewerID should be set');
+ const op: DMSendEditMessageOperation = {
+ type: 'send_edit_message',
+ threadID: threadInfo.id,
+ creatorID: viewerID,
+ time: Date.now(),
+ messageID: uuid.v4(),
+ targetMessageID: messageID,
+ text: newText,
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+ await utils.processAndSendDMOperation(opSpecification);
+ },
+
+ changeThreadSettings: async (
+ protocolInput: ProtocolChangeThreadSettingsInput,
+ utils: ChangeThreadSettingsUtils,
+ ) => {
+ const { viewerID, input } = protocolInput;
+ invariant(viewerID, 'viewerID should be set');
+ invariant(
+ !input.changes.newMemberIDs,
+ "DM protocol doesn't support" +
+ ' adding new members when changing thread settings',
+ );
+
+ const changes: { ...DMThreadSettingsChanges } = {};
+ if (input.changes.name) {
+ changes.name = input.changes.name;
+ }
+ if (input.changes.description) {
+ changes.description = input.changes.description;
+ }
+ if (input.changes.color) {
+ changes.color = input.changes.color;
+ }
+ if (input.changes.avatar && input.changes.avatar.type === 'emoji') {
+ changes.avatar = {
+ type: 'emoji',
+ emoji: input.changes.avatar.emoji,
+ color: input.changes.avatar.color,
+ };
+ } else if (input.changes.avatar && input.changes.avatar.type === 'ens') {
+ changes.avatar = { type: 'ens' };
+ } else if (
+ input.changes.avatar &&
+ input.changes.avatar.type === 'non_keyserver_image'
+ ) {
+ changes.avatar = {
+ type: 'encrypted_image',
+ blobURI: input.changes.avatar.blobURI,
+ thumbHash: input.changes.avatar.thumbHash,
+ encryptionKey: input.changes.avatar.encryptionKey,
+ };
+ } else if (
+ input.changes.avatar &&
+ input.changes.avatar.type === 'remove'
+ ) {
+ changes.avatar = null;
+ }
+
+ const { threadInfo } = input;
+ const op: DMChangeThreadSettingsOperation = {
+ type: 'change_thread_settings',
+ threadID: threadInfo.id,
+ editorID: viewerID,
+ time: Date.now(),
+ changes,
+ messageIDsPrefix: uuid.v4(),
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
};
- } else if (input.changes.avatar && input.changes.avatar.type === 'remove') {
- changes.avatar = null;
- }
-
- const { threadInfo } = input;
- const op: DMChangeThreadSettingsOperation = {
- type: 'change_thread_settings',
- threadID: threadInfo.id,
- editorID: viewerID,
- time: Date.now(),
- changes,
- messageIDsPrefix: uuid.v4(),
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
-
- await utils.processAndSendDMOperation(opSpecification);
- return ({
- threadID: threadInfo.id,
- updatesResult: { newUpdates: [] },
- newMessageInfos: [],
- }: ChangeThreadSettingsPayload);
- },
-
- supportsCalendarHistory: false,
-
- calendarIsOnline: (tunnelbrokerSocketState: TunnelbrokerSocketState) =>
- !!tunnelbrokerSocketState.connected,
-
- createCalendarEntry: async (
- protocolInput: ProtocolCreateEntryInput,
- utils: CreateEntryUtils,
- ) => {
- const { viewerID, input } = protocolInput;
-
- invariant(viewerID, 'viewerID must be set');
- const entryID = uuid.v4();
-
- const { createEntryInfo, threadInfo } = input;
- const op: DMCreateEntryOperation = {
- type: 'create_entry',
- threadID: threadInfo.id,
- creatorID: viewerID,
- time: createEntryInfo.timestamp,
- entryID: uuid.v4(),
- entryDate: createEntryInfo.date,
- text: createEntryInfo.text,
- messageID: uuid.v4(),
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
-
- await utils.processAndSendDMOperation(opSpecification);
-
- return {
- entryID,
- newMessageInfos: [],
- threadID: createEntryInfo.threadID,
- localID: createEntryInfo.localID,
- updatesResult: {
- viewerUpdates: [],
- userInfos: [],
- },
- };
- },
-
- deleteCalendarEntry: async (
- protocolInput: ProtocolDeleteEntryInput,
- utils: DeleteEntryUtils,
- ) => {
- const { viewerID, input, originalEntry: prevEntry } = protocolInput;
- const { deleteEntryInfo, threadInfo } = input;
-
- invariant(viewerID, 'viewerID must be set');
-
- const op: DMDeleteEntryOperation = {
- type: 'delete_entry',
- threadID: threadInfo.id,
- creatorID: viewerID,
- creationTime: prevEntry.creationTime,
- time: Date.now(),
- entryID: deleteEntryInfo.entryID,
- entryDate: stringFromDate(prevEntry.year, prevEntry.month, prevEntry.day),
- prevText: deleteEntryInfo.prevText,
- messageID: uuid.v4(),
- };
-
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
-
- await utils.processAndSendDMOperation(opSpecification);
-
- return {
- threadID: threadInfo.id,
- newMessageInfos: [],
- updatesResult: {
- viewerUpdates: [],
- userInfos: [],
- },
- };
- },
-
- editCalendarEntry: async (
- protocolInput: ProtocolEditEntryInput,
- utils: EditEntryUtils,
- ) => {
- const { viewerID, input, originalEntry: prevEntry } = protocolInput;
- const { saveEntryInfo, threadInfo } = input;
-
- invariant(viewerID, 'viewerID must be set');
-
- const op: DMEditEntryOperation = {
- type: 'edit_entry',
- threadID: threadInfo.id,
- creatorID: viewerID,
- creationTime: prevEntry.creationTime,
- time: saveEntryInfo.timestamp,
- entryID: saveEntryInfo.entryID,
- entryDate: stringFromDate(prevEntry.year, prevEntry.month, prevEntry.day),
- text: saveEntryInfo.text,
- messageID: uuid.v4(),
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
-
- await utils.processAndSendDMOperation(opSpecification);
-
- return {
- entryID: saveEntryInfo.entryID,
- newMessageInfos: [],
- updatesResult: {
- viewerUpdates: [],
- userInfos: [],
- },
- };
- },
-
- setThreadUnreadStatus: async (
- input: ProtocolSetThreadUnreadStatusInput,
- utils: SetThreadUnreadStatusUtils,
- ) => {
- const {
- viewerID,
- input: { threadInfo },
- } = input;
-
- invariant(viewerID, 'viewerID must be set');
- const op: DMChangeThreadReadStatusOperation = {
- type: 'change_thread_read_status',
- time: Date.now(),
- threadID: threadInfo.id,
- creatorID: viewerID,
- unread: !threadInfo.currentUser.unread,
- };
-
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'self_devices',
- },
- };
-
- await utils.processAndSendDMOperation(opSpecification);
- return {
- resetToUnread: false,
- threadID: threadInfo.id,
- };
- },
-
- sendReaction: async (
- input: ProtocolSendReactionInput,
- utils: SendReactionUtils,
- ) => {
- const { threadInfo, viewerID, messageID, reaction, action } = input;
- const threadID = threadInfo.id;
-
- const op: DMSendReactionMessageOperation = {
- type: 'send_reaction_message',
- threadID,
- creatorID: viewerID,
- time: Date.now(),
- messageID: uuid.v4(),
- targetMessageID: messageID,
- reaction,
- action,
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
- await utils.processAndSendDMOperation(opSpecification);
- },
-
- addThreadMembers: (
- input: ProtocolAddThreadMembersInput,
- utils: AddThreadMembersUtils,
- ) => utils.dmAddThreadMembers(input.newMemberIDs, input.threadInfo),
-
- updateSubscription: async (
- protocolInput: ProtocolUpdateSubscriptionInput,
- utils: UpdateSubscriptionUtils,
- ) => {
- const { viewerID, input } = protocolInput;
- invariant(viewerID, 'viewerID must be set');
-
- const { threadInfo, updatedFields } = input;
- const subscription = {
- ...threadInfo.currentUser.subscription,
- ...updatedFields,
- };
-
- const op: DMChangeThreadSubscriptionOperation = {
- type: 'change_thread_subscription',
- time: Date.now(),
- threadID: threadInfo.id,
- creatorID: viewerID,
- subscription,
- };
-
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
-
- await utils.processAndSendDMOperation(opSpecification);
- return { threadID: threadInfo.id, subscription };
- },
-
- leaveThread: async (
- input: ProtocolLeaveThreadInput,
- utils: LeaveThreadUtils,
- ) => {
- const { threadInfo, viewerID } = input;
- invariant(viewerID, 'viewerID should be set');
- const op: DMLeaveThreadOperation = {
- type: 'leave_thread',
- editorID: viewerID,
- time: Date.now(),
- messageID: uuid.v4(),
- threadID: threadInfo.id,
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
- await utils.processAndSendDMOperation(opSpecification);
- return {
- invalidatedThreads: [],
- };
- },
-
- allowsDeletingSidebarSource: false,
-
- presentationDetails: {
- membershipChangesShownInThreadPreview: true,
- usersWithoutDeviceListExcludedFromSearchResult: true,
- supportsMediaGallery: false,
- nativeChatThreadListIcon: 'lock',
- webChatThreadListIcon: 'lock',
- threadAncestorLabel: () => 'Local DM',
- },
-
- uploadMultimediaMetadataToKeyserver: false,
-
- canActionsTargetPendingMessages: true,
-
- sidebarConfig: {
- sidebarThreadType: thickThreadTypes.THICK_SIDEBAR,
- pendingSidebarURLPrefix: pendingThickSidebarURLPrefix,
- },
-
- shouldPerformSideEffectsBeforeSendingMessage: false,
-
- messagesStoredOnServer: false,
-
- arePendingThreadsDescendantsOfGenesis: false,
-
- threadActivityUpdatedByDMActivityHandler: true,
-});
+
+ await utils.processAndSendDMOperation(opSpecification);
+ return ({
+ threadID: threadInfo.id,
+ updatesResult: { newUpdates: [] },
+ newMessageInfos: [],
+ }: ChangeThreadSettingsPayload);
+ },
+
+ supportsCalendarHistory: false,
+
+ calendarIsOnline: (tunnelbrokerSocketState: TunnelbrokerSocketState) =>
+ !!tunnelbrokerSocketState.connected,
+
+ createCalendarEntry: async (
+ protocolInput: ProtocolCreateEntryInput,
+ utils: CreateEntryUtils,
+ ) => {
+ const { viewerID, input } = protocolInput;
+
+ invariant(viewerID, 'viewerID must be set');
+ const entryID = uuid.v4();
+
+ const { createEntryInfo, threadInfo } = input;
+ const op: DMCreateEntryOperation = {
+ type: 'create_entry',
+ threadID: threadInfo.id,
+ creatorID: viewerID,
+ time: createEntryInfo.timestamp,
+ entryID: uuid.v4(),
+ entryDate: createEntryInfo.date,
+ text: createEntryInfo.text,
+ messageID: uuid.v4(),
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+
+ await utils.processAndSendDMOperation(opSpecification);
+
+ return {
+ entryID,
+ newMessageInfos: [],
+ threadID: createEntryInfo.threadID,
+ localID: createEntryInfo.localID,
+ updatesResult: {
+ viewerUpdates: [],
+ userInfos: [],
+ },
+ };
+ },
+
+ deleteCalendarEntry: async (
+ protocolInput: ProtocolDeleteEntryInput,
+ utils: DeleteEntryUtils,
+ ) => {
+ const { viewerID, input, originalEntry: prevEntry } = protocolInput;
+ const { deleteEntryInfo, threadInfo } = input;
+
+ invariant(viewerID, 'viewerID must be set');
+
+ const op: DMDeleteEntryOperation = {
+ type: 'delete_entry',
+ threadID: threadInfo.id,
+ creatorID: viewerID,
+ creationTime: prevEntry.creationTime,
+ time: Date.now(),
+ entryID: deleteEntryInfo.entryID,
+ entryDate: stringFromDate(
+ prevEntry.year,
+ prevEntry.month,
+ prevEntry.day,
+ ),
+ prevText: deleteEntryInfo.prevText,
+ messageID: uuid.v4(),
+ };
+
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+
+ await utils.processAndSendDMOperation(opSpecification);
+
+ return {
+ threadID: threadInfo.id,
+ newMessageInfos: [],
+ updatesResult: {
+ viewerUpdates: [],
+ userInfos: [],
+ },
+ };
+ },
+
+ editCalendarEntry: async (
+ protocolInput: ProtocolEditEntryInput,
+ utils: EditEntryUtils,
+ ) => {
+ const { viewerID, input, originalEntry: prevEntry } = protocolInput;
+ const { saveEntryInfo, threadInfo } = input;
+
+ invariant(viewerID, 'viewerID must be set');
+
+ const op: DMEditEntryOperation = {
+ type: 'edit_entry',
+ threadID: threadInfo.id,
+ creatorID: viewerID,
+ creationTime: prevEntry.creationTime,
+ time: saveEntryInfo.timestamp,
+ entryID: saveEntryInfo.entryID,
+ entryDate: stringFromDate(
+ prevEntry.year,
+ prevEntry.month,
+ prevEntry.day,
+ ),
+ text: saveEntryInfo.text,
+ messageID: uuid.v4(),
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+
+ await utils.processAndSendDMOperation(opSpecification);
+
+ return {
+ entryID: saveEntryInfo.entryID,
+ newMessageInfos: [],
+ updatesResult: {
+ viewerUpdates: [],
+ userInfos: [],
+ },
+ };
+ },
+
+ setThreadUnreadStatus: async (
+ input: ProtocolSetThreadUnreadStatusInput,
+ utils: SetThreadUnreadStatusUtils,
+ ) => {
+ const {
+ viewerID,
+ input: { threadInfo },
+ } = input;
+
+ invariant(viewerID, 'viewerID must be set');
+ const op: DMChangeThreadReadStatusOperation = {
+ type: 'change_thread_read_status',
+ time: Date.now(),
+ threadID: threadInfo.id,
+ creatorID: viewerID,
+ unread: !threadInfo.currentUser.unread,
+ };
+
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'self_devices',
+ },
+ };
+
+ await utils.processAndSendDMOperation(opSpecification);
+ return {
+ resetToUnread: false,
+ threadID: threadInfo.id,
+ };
+ },
+
+ sendReaction: async (
+ input: ProtocolSendReactionInput,
+ utils: SendReactionUtils,
+ ) => {
+ const { threadInfo, viewerID, messageID, reaction, action } = input;
+ const threadID = threadInfo.id;
+
+ const op: DMSendReactionMessageOperation = {
+ type: 'send_reaction_message',
+ threadID,
+ creatorID: viewerID,
+ time: Date.now(),
+ messageID: uuid.v4(),
+ targetMessageID: messageID,
+ reaction,
+ action,
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+ await utils.processAndSendDMOperation(opSpecification);
+ },
+
+ addThreadMembers: (
+ input: ProtocolAddThreadMembersInput,
+ utils: AddThreadMembersUtils,
+ ) => utils.dmAddThreadMembers(input.newMemberIDs, input.threadInfo),
+
+ updateSubscription: async (
+ protocolInput: ProtocolUpdateSubscriptionInput,
+ utils: UpdateSubscriptionUtils,
+ ) => {
+ const { viewerID, input } = protocolInput;
+ invariant(viewerID, 'viewerID must be set');
+
+ const { threadInfo, updatedFields } = input;
+ const subscription = {
+ ...threadInfo.currentUser.subscription,
+ ...updatedFields,
+ };
+
+ const op: DMChangeThreadSubscriptionOperation = {
+ type: 'change_thread_subscription',
+ time: Date.now(),
+ threadID: threadInfo.id,
+ creatorID: viewerID,
+ subscription,
+ };
+
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+
+ await utils.processAndSendDMOperation(opSpecification);
+ return { threadID: threadInfo.id, subscription };
+ },
+
+ leaveThread: async (
+ input: ProtocolLeaveThreadInput,
+ utils: LeaveThreadUtils,
+ ) => {
+ const { threadInfo, viewerID } = input;
+ invariant(viewerID, 'viewerID should be set');
+ const op: DMLeaveThreadOperation = {
+ type: 'leave_thread',
+ editorID: viewerID,
+ time: Date.now(),
+ messageID: uuid.v4(),
+ threadID: threadInfo.id,
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+ await utils.processAndSendDMOperation(opSpecification);
+ return {
+ invalidatedThreads: [],
+ };
+ },
+
+ convertClientDBThreadInfo: (
+ clientDBThreadInfo: ClientDBThreadInfo,
+ members: $ReadOnlyArray<MinimallyEncodedThickMemberInfo>,
+ roles: { +[id: string]: RoleInfo },
+ currentUser: ThreadCurrentUserInfo,
+ ) => {
+ const thickThreadType = assertThickThreadType(clientDBThreadInfo.type);
+
+ invariant(
+ clientDBThreadInfo.timestamps,
+ 'Thick thread info must contain the timestamps',
+ );
+ const threadTimestamps = assertWithValidator(
+ JSON.parse(clientDBThreadInfo.timestamps),
+ threadTimestampsValidator,
+ );
+
+ let rawThreadInfo: ThickRawThreadInfo = {
+ minimallyEncoded: true,
+ thick: true,
+ id: clientDBThreadInfo.id,
+ type: thickThreadType,
+ name: clientDBThreadInfo.name,
+ description: clientDBThreadInfo.description,
+ color: clientDBThreadInfo.color,
+ creationTime: Number(clientDBThreadInfo.creationTime),
+ parentThreadID: clientDBThreadInfo.parentThreadID,
+ containingThreadID: clientDBThreadInfo.containingThreadID,
+ members,
+ roles,
+ currentUser,
+ repliesCount: clientDBThreadInfo.repliesCount,
+ pinnedCount: clientDBThreadInfo.pinnedCount,
+ timestamps: threadTimestamps,
+ };
+
+ if (clientDBThreadInfo.sourceMessageID) {
+ rawThreadInfo = {
+ ...rawThreadInfo,
+ sourceMessageID: clientDBThreadInfo.sourceMessageID,
+ };
+ }
+
+ if (clientDBThreadInfo.avatar) {
+ rawThreadInfo = {
+ ...rawThreadInfo,
+ avatar: JSON.parse(clientDBThreadInfo.avatar),
+ };
+ }
+
+ return rawThreadInfo;
+ },
+
+ allowsDeletingSidebarSource: false,
+
+ presentationDetails: {
+ membershipChangesShownInThreadPreview: true,
+ usersWithoutDeviceListExcludedFromSearchResult: true,
+ supportsMediaGallery: false,
+ nativeChatThreadListIcon: 'lock',
+ webChatThreadListIcon: 'lock',
+ threadAncestorLabel: () => 'Local DM',
+ },
+
+ uploadMultimediaMetadataToKeyserver: false,
+
+ canActionsTargetPendingMessages: true,
+
+ sidebarConfig: {
+ sidebarThreadType: thickThreadTypes.THICK_SIDEBAR,
+ pendingSidebarURLPrefix: pendingThickSidebarURLPrefix,
+ },
+
+ shouldPerformSideEffectsBeforeSendingMessage: false,
+
+ messagesStoredOnServer: false,
+
+ arePendingThreadsDescendantsOfGenesis: false,
+
+ threadActivityUpdatedByDMActivityHandler: true,
+ });
export { dmThreadProtocol };
diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js
--- a/lib/shared/threads/protocols/keyserver-thread-protocol.js
+++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js
@@ -36,8 +36,18 @@
} from '../../../types/message-types.js';
import { getMediaMessageServerDBContentsFromMedia } from '../../../types/messages/media.js';
import type { RawReactionMessageInfo } from '../../../types/messages/reaction.js';
+import type {
+ RoleInfo,
+ ThreadCurrentUserInfo,
+ ThinRawThreadInfo,
+ MemberInfoSansPermissions,
+} from '../../../types/minimally-encoded-thread-permissions-types.js';
import type { Dispatch } from '../../../types/redux-types.js';
-import { thinThreadTypes } from '../../../types/thread-types-enum.js';
+import {
+ assertThinThreadType,
+ thinThreadTypes,
+} from '../../../types/thread-types-enum.js';
+import type { ClientDBThreadInfo } from '../../../types/thread-types.js';
import {
blobHashFromBlobServiceURI,
isBlobServiceURI,
@@ -77,50 +87,79 @@
LeaveThreadUtils,
} from '../thread-spec.js';
-const keyserverThreadProtocol: ThreadProtocol = Object.freeze({
- sendTextMessage: async (
- message: ProtocolSendTextMessageInput,
- utils: SendTextMessageUtils,
- ) => {
- const { messageInfo, sidebarCreation } = message;
- const { localID } = messageInfo;
- invariant(
- localID !== null && localID !== undefined,
- 'localID should be set',
- );
- const result = await utils.sendKeyserverTextMessage({
- threadID: messageInfo.threadID,
- localID,
- text: messageInfo.text,
- sidebarCreation,
- });
- return {
- localID,
- serverID: result.id,
- threadID: messageInfo.threadID,
- time: result.time,
- };
- },
+const keyserverThreadProtocol: ThreadProtocol<MemberInfoSansPermissions> =
+ Object.freeze({
+ sendTextMessage: async (
+ message: ProtocolSendTextMessageInput,
+ utils: SendTextMessageUtils,
+ ) => {
+ const { messageInfo, sidebarCreation } = message;
+ const { localID } = messageInfo;
+ invariant(
+ localID !== null && localID !== undefined,
+ 'localID should be set',
+ );
+ const result = await utils.sendKeyserverTextMessage({
+ threadID: messageInfo.threadID,
+ localID,
+ text: messageInfo.text,
+ sidebarCreation,
+ });
+ return {
+ localID,
+ serverID: result.id,
+ threadID: messageInfo.threadID,
+ time: result.time,
+ };
+ },
- sendMultimediaMessage: async (
- message: ProtocolSendMultimediaMessageInput,
- utils: SendMultimediaMessageUtils,
- ) => {
- const { messageInfo, isLegacy, sidebarCreation } = message;
- const { localID } = messageInfo;
- invariant(
- localID !== null && localID !== undefined,
- 'localID should be set',
- );
+ sendMultimediaMessage: async (
+ message: ProtocolSendMultimediaMessageInput,
+ utils: SendMultimediaMessageUtils,
+ ) => {
+ const { messageInfo, isLegacy, sidebarCreation } = message;
+ const { localID } = messageInfo;
+ invariant(
+ localID !== null && localID !== undefined,
+ 'localID should be set',
+ );
+
+ const {
+ reassignThickThreadMedia,
+ dispatch,
+ processHolders,
+ legacyKeyserverSendMultimediaMessage,
+ sendKeyserverMultimediaMessage,
+ } = utils;
+ if (isLegacy) {
+ const { messageMedia, mediaIDUpdates } =
+ await migrateMessageMediaToKeyserver(
+ messageInfo,
+ reassignThickThreadMedia,
+ dispatch,
+ processHolders,
+ );
+ const mediaIDs = [];
+ for (const { id } of messageMedia) {
+ mediaIDs.push(id);
+ }
+ const result = await legacyKeyserverSendMultimediaMessage({
+ threadID: messageInfo.threadID,
+ localID,
+ mediaIDs,
+ sidebarCreation,
+ });
+ return {
+ result: {
+ localID,
+ serverID: result.id,
+ threadID: messageInfo.threadID,
+ time: result.time,
+ },
+ mediaIDUpdates,
+ };
+ }
- const {
- reassignThickThreadMedia,
- dispatch,
- processHolders,
- legacyKeyserverSendMultimediaMessage,
- sendKeyserverMultimediaMessage,
- } = utils;
- if (isLegacy) {
const { messageMedia, mediaIDUpdates } =
await migrateMessageMediaToKeyserver(
messageInfo,
@@ -128,14 +167,12 @@
dispatch,
processHolders,
);
- const mediaIDs = [];
- for (const { id } of messageMedia) {
- mediaIDs.push(id);
- }
- const result = await legacyKeyserverSendMultimediaMessage({
+ const mediaMessageContents =
+ getMediaMessageServerDBContentsFromMedia(messageMedia);
+ const result = await sendKeyserverMultimediaMessage({
threadID: messageInfo.threadID,
localID,
- mediaIDs,
+ mediaMessageContents,
sidebarCreation,
});
return {
@@ -147,237 +184,254 @@
},
mediaIDUpdates,
};
- }
+ },
- const { messageMedia, mediaIDUpdates } =
- await migrateMessageMediaToKeyserver(
- messageInfo,
- reassignThickThreadMedia,
- dispatch,
- processHolders,
+ editTextMessage: async (
+ message: ProtocolEditTextMessageInput,
+ utils: EditTextMessageUtils,
+ ) => {
+ const { messageID, newText } = message;
+ const editMessagePromise = (async () => {
+ const result = await utils.keyserverEditMessage({
+ targetMessageID: messageID,
+ text: newText,
+ });
+
+ return ({
+ newMessageInfos: result.newMessageInfos,
+ }: { +newMessageInfos: $ReadOnlyArray<RawMessageInfo> });
+ })();
+
+ void utils.dispatchActionPromise(
+ sendEditMessageActionTypes,
+ editMessagePromise,
);
- const mediaMessageContents =
- getMediaMessageServerDBContentsFromMedia(messageMedia);
- const result = await sendKeyserverMultimediaMessage({
- threadID: messageInfo.threadID,
- localID,
- mediaMessageContents,
- sidebarCreation,
- });
- return {
- result: {
- localID,
- serverID: result.id,
- threadID: messageInfo.threadID,
- time: result.time,
- },
- mediaIDUpdates,
- };
- },
- editTextMessage: async (
- message: ProtocolEditTextMessageInput,
- utils: EditTextMessageUtils,
- ) => {
- const { messageID, newText } = message;
- const editMessagePromise = (async () => {
- const result = await utils.keyserverEditMessage({
+ await editMessagePromise;
+ },
+
+ changeThreadSettings: async (
+ protocolInput: ProtocolChangeThreadSettingsInput,
+ utils: ChangeThreadSettingsUtils,
+ ) => {
+ const { threadInfo, ...rest } = protocolInput.input;
+ return await utils.keyserverChangeThreadSettings({ ...rest });
+ },
+
+ supportsCalendarHistory: true,
+
+ calendarIsOnline: (
+ tunnelbrokerSocketState: TunnelbrokerSocketState,
+ isKeyserverConnected: boolean,
+ ) => isKeyserverConnected,
+
+ createCalendarEntry: (
+ protocolInput: ProtocolCreateEntryInput,
+ utils: CreateEntryUtils,
+ ) => utils.keyserverCreateEntry(protocolInput.input.createEntryInfo),
+
+ deleteCalendarEntry: (
+ protocolInput: ProtocolDeleteEntryInput,
+ utils: DeleteEntryUtils,
+ ) => utils.keyserverDeleteEntry(protocolInput.input.deleteEntryInfo),
+
+ editCalendarEntry: (
+ protocolInput: ProtocolEditEntryInput,
+ utils: EditEntryUtils,
+ ) => utils.keyserverEditEntry(protocolInput.input.saveEntryInfo),
+
+ setThreadUnreadStatus: (
+ input: ProtocolSetThreadUnreadStatusInput,
+ utils: SetThreadUnreadStatusUtils,
+ ) => {
+ const {
+ input: { threadInfo, ...rest },
+ } = input;
+ return utils.keyserverSetThreadUnreadStatus(rest);
+ },
+
+ sendReaction: async (
+ input: ProtocolSendReactionInput,
+ utils: SendReactionUtils,
+ ) => {
+ const {
+ threadInfo,
+ viewerID,
+ messageID,
+ reaction,
+ action,
+ showErrorAlert,
+ } = input;
+ const threadID = threadInfo.id;
+ const localID = getNextLocalID();
+
+ const reactionMessagePromise = (async () => {
+ try {
+ const result = await utils.keyserverSendReaction({
+ threadID,
+ localID,
+ targetMessageID: messageID,
+ reaction,
+ action,
+ });
+ return {
+ localID,
+ serverID: result.id,
+ threadID,
+ time: result.time,
+ };
+ } catch (e) {
+ showErrorAlert();
+ const exceptionMessage = getMessageForException(e) ?? '';
+ throw new SendMessageError(
+ `Exception while sending reaction: ${exceptionMessage}`,
+ localID,
+ threadID,
+ );
+ }
+ })();
+
+ const startingPayload: RawReactionMessageInfo = {
+ type: messageTypes.REACTION,
+ threadID,
+ localID,
+ creatorID: viewerID,
+ time: Date.now(),
targetMessageID: messageID,
- text: newText,
- });
+ reaction,
+ action,
+ };
- return ({
- newMessageInfos: result.newMessageInfos,
- }: { +newMessageInfos: $ReadOnlyArray<RawMessageInfo> });
- })();
+ void utils.dispatchActionPromise(
+ sendReactionMessageActionTypes,
+ reactionMessagePromise,
+ undefined,
+ startingPayload,
+ );
- void utils.dispatchActionPromise(
- sendEditMessageActionTypes,
- editMessagePromise,
- );
+ await reactionMessagePromise;
+ },
- await editMessagePromise;
- },
+ addThreadMembers: async (
+ input: ProtocolAddThreadMembersInput,
+ utils: AddThreadMembersUtils,
+ ) => {
+ const { threadInfo, newMemberIDs } = input;
- changeThreadSettings: async (
- protocolInput: ProtocolChangeThreadSettingsInput,
- utils: ChangeThreadSettingsUtils,
- ) => {
- const { threadInfo, ...rest } = protocolInput.input;
- return await utils.keyserverChangeThreadSettings({ ...rest });
- },
-
- supportsCalendarHistory: true,
-
- calendarIsOnline: (
- tunnelbrokerSocketState: TunnelbrokerSocketState,
- isKeyserverConnected: boolean,
- ) => isKeyserverConnected,
-
- createCalendarEntry: (
- protocolInput: ProtocolCreateEntryInput,
- utils: CreateEntryUtils,
- ) => utils.keyserverCreateEntry(protocolInput.input.createEntryInfo),
-
- deleteCalendarEntry: (
- protocolInput: ProtocolDeleteEntryInput,
- utils: DeleteEntryUtils,
- ) => utils.keyserverDeleteEntry(protocolInput.input.deleteEntryInfo),
-
- editCalendarEntry: (
- protocolInput: ProtocolEditEntryInput,
- utils: EditEntryUtils,
- ) => utils.keyserverEditEntry(protocolInput.input.saveEntryInfo),
-
- setThreadUnreadStatus: (
- input: ProtocolSetThreadUnreadStatusInput,
- utils: SetThreadUnreadStatusUtils,
- ) => {
- const {
- input: { threadInfo, ...rest },
- } = input;
- return utils.keyserverSetThreadUnreadStatus(rest);
- },
-
- sendReaction: async (
- input: ProtocolSendReactionInput,
- utils: SendReactionUtils,
- ) => {
- const {
- threadInfo,
- viewerID,
- messageID,
- reaction,
- action,
- showErrorAlert,
- } = input;
- const threadID = threadInfo.id;
- const localID = getNextLocalID();
-
- const reactionMessagePromise = (async () => {
- try {
- const result = await utils.keyserverSendReaction({
- threadID,
- localID,
- targetMessageID: messageID,
- reaction,
- action,
- });
- return {
- localID,
- serverID: result.id,
- threadID,
- time: result.time,
- };
- } catch (e) {
- showErrorAlert();
- const exceptionMessage = getMessageForException(e) ?? '';
- throw new SendMessageError(
- `Exception while sending reaction: ${exceptionMessage}`,
- localID,
- threadID,
- );
- }
- })();
-
- const startingPayload: RawReactionMessageInfo = {
- type: messageTypes.REACTION,
- threadID,
- localID,
- creatorID: viewerID,
- time: Date.now(),
- targetMessageID: messageID,
- reaction,
- action,
- };
+ const changeThreadSettingsInput = {
+ threadInfo,
+ threadID: threadInfo.id,
+ changes: { newMemberIDs },
+ };
- void utils.dispatchActionPromise(
- sendReactionMessageActionTypes,
- reactionMessagePromise,
- undefined,
- startingPayload,
- );
+ const addMembersPromise = utils.changeThreadSettings(
+ changeThreadSettingsInput,
+ );
- await reactionMessagePromise;
- },
+ void utils.dispatchActionPromise(
+ changeThreadSettingsActionTypes,
+ addMembersPromise,
+ );
+ await addMembersPromise;
+ },
- addThreadMembers: async (
- input: ProtocolAddThreadMembersInput,
- utils: AddThreadMembersUtils,
- ) => {
- const { threadInfo, newMemberIDs } = input;
+ updateSubscription: (
+ protocolInput: ProtocolUpdateSubscriptionInput,
+ utils: UpdateSubscriptionUtils,
+ ) => {
+ const { threadInfo, ...rest } = protocolInput.input;
+ return utils.keyserverUpdateSubscription(rest);
+ },
- const changeThreadSettingsInput = {
- threadInfo,
- threadID: threadInfo.id,
- changes: { newMemberIDs },
- };
+ leaveThread: async (
+ input: ProtocolLeaveThreadInput,
+ utils: LeaveThreadUtils,
+ ) => {
+ const threadID = input.threadInfo.id;
+ const promise = utils.keyserverLeaveThread({ threadID });
+ void utils.dispatchActionPromise(leaveThreadActionTypes, promise, {
+ customKeyName: `${leaveThreadActionTypes.started}:${threadID}`,
+ });
+ const result = await promise;
+ const invalidated = identifyInvalidatedThreads(
+ result.updatesResult.newUpdates,
+ );
+ return {
+ invalidatedThreads: [...invalidated],
+ };
+ },
- const addMembersPromise = utils.changeThreadSettings(
- changeThreadSettingsInput,
- );
+ convertClientDBThreadInfo: (
+ clientDBThreadInfo: ClientDBThreadInfo,
+ members: $ReadOnlyArray<MemberInfoSansPermissions>,
+ roles: { +[id: string]: RoleInfo },
+ currentUser: ThreadCurrentUserInfo,
+ ) => {
+ const thinThreadType = assertThinThreadType(clientDBThreadInfo.type);
+
+ let rawThreadInfo: ThinRawThreadInfo = {
+ minimallyEncoded: true,
+ id: clientDBThreadInfo.id,
+ type: thinThreadType,
+ name: clientDBThreadInfo.name,
+ description: clientDBThreadInfo.description,
+ color: clientDBThreadInfo.color,
+ creationTime: Number(clientDBThreadInfo.creationTime),
+ parentThreadID: clientDBThreadInfo.parentThreadID,
+ containingThreadID: clientDBThreadInfo.containingThreadID,
+ community: clientDBThreadInfo.community,
+ members,
+ roles,
+ currentUser,
+ repliesCount: clientDBThreadInfo.repliesCount,
+ pinnedCount: clientDBThreadInfo.pinnedCount,
+ };
- void utils.dispatchActionPromise(
- changeThreadSettingsActionTypes,
- addMembersPromise,
- );
- await addMembersPromise;
- },
+ if (clientDBThreadInfo.sourceMessageID) {
+ rawThreadInfo = {
+ ...rawThreadInfo,
+ sourceMessageID: clientDBThreadInfo.sourceMessageID,
+ };
+ }
- updateSubscription: (
- protocolInput: ProtocolUpdateSubscriptionInput,
- utils: UpdateSubscriptionUtils,
- ) => {
- const { threadInfo, ...rest } = protocolInput.input;
- return utils.keyserverUpdateSubscription(rest);
- },
+ if (clientDBThreadInfo.avatar) {
+ rawThreadInfo = {
+ ...rawThreadInfo,
+ avatar: JSON.parse(clientDBThreadInfo.avatar),
+ };
+ }
- leaveThread: async (
- input: ProtocolLeaveThreadInput,
- utils: LeaveThreadUtils,
- ) => {
- const threadID = input.threadInfo.id;
- const promise = utils.keyserverLeaveThread({ threadID });
- void utils.dispatchActionPromise(leaveThreadActionTypes, promise, {
- customKeyName: `${leaveThreadActionTypes.started}:${threadID}`,
- });
- const result = await promise;
- const invalidated = identifyInvalidatedThreads(
- result.updatesResult.newUpdates,
- );
- return {
- invalidatedThreads: [...invalidated],
- };
- },
+ return rawThreadInfo;
+ },
- allowsDeletingSidebarSource: true,
+ allowsDeletingSidebarSource: true,
- presentationDetails: {
- membershipChangesShownInThreadPreview: false,
- usersWithoutDeviceListExcludedFromSearchResult: false,
- supportsMediaGallery: true,
- nativeChatThreadListIcon: 'server',
- webChatThreadListIcon: 'server',
- threadAncestorLabel: (ancestorPath: React.Node) => ancestorPath,
- },
+ presentationDetails: {
+ membershipChangesShownInThreadPreview: false,
+ usersWithoutDeviceListExcludedFromSearchResult: false,
+ supportsMediaGallery: true,
+ nativeChatThreadListIcon: 'server',
+ webChatThreadListIcon: 'server',
+ threadAncestorLabel: (ancestorPath: React.Node) => ancestorPath,
+ },
- uploadMultimediaMetadataToKeyserver: true,
+ uploadMultimediaMetadataToKeyserver: true,
- canActionsTargetPendingMessages: false,
+ canActionsTargetPendingMessages: false,
- sidebarConfig: {
- sidebarThreadType: thinThreadTypes.SIDEBAR,
- pendingSidebarURLPrefix: pendingSidebarURLPrefix,
- },
+ sidebarConfig: {
+ sidebarThreadType: thinThreadTypes.SIDEBAR,
+ pendingSidebarURLPrefix: pendingSidebarURLPrefix,
+ },
- shouldPerformSideEffectsBeforeSendingMessage: true,
+ shouldPerformSideEffectsBeforeSendingMessage: true,
- messagesStoredOnServer: true,
+ messagesStoredOnServer: true,
- arePendingThreadsDescendantsOfGenesis: true,
+ arePendingThreadsDescendantsOfGenesis: true,
- threadActivityUpdatedByDMActivityHandler: false,
-});
+ threadActivityUpdatedByDMActivityHandler: false,
+ });
function mediaIDIsKeyserverID(mediaID: string): boolean {
return mediaID.indexOf('|') !== -1;
diff --git a/lib/shared/threads/sidebar-spec.js b/lib/shared/threads/sidebar-spec.js
--- a/lib/shared/threads/sidebar-spec.js
+++ b/lib/shared/threads/sidebar-spec.js
@@ -2,8 +2,9 @@
import { keyserverThreadProtocol } from './protocols/keyserver-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
-const sidebarSpec: ThreadSpec = Object.freeze({
+const sidebarSpec: ThreadSpec<MemberInfoSansPermissions> = Object.freeze({
traits: new Set(['sidebar']),
protocol: keyserverThreadProtocol,
threadLabel: 'Thread',
diff --git a/lib/shared/threads/thick-sidebar-spec.js b/lib/shared/threads/thick-sidebar-spec.js
--- a/lib/shared/threads/thick-sidebar-spec.js
+++ b/lib/shared/threads/thick-sidebar-spec.js
@@ -2,11 +2,13 @@
import { dmThreadProtocol } from './protocols/dm-thread-protocol.js';
import type { ThreadSpec } from './thread-spec.js';
+import type { MinimallyEncodedThickMemberInfo } from '../../types/minimally-encoded-thread-permissions-types.js';
-const thickSidebarSpec: ThreadSpec = Object.freeze({
- traits: new Set(['sidebar']),
- protocol: dmThreadProtocol,
- threadLabel: 'Thread',
-});
+const thickSidebarSpec: ThreadSpec<MinimallyEncodedThickMemberInfo> =
+ Object.freeze({
+ traits: new Set(['sidebar']),
+ protocol: dmThreadProtocol,
+ threadLabel: 'Thread',
+ });
export { thickSidebarSpec };
diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js
--- a/lib/shared/threads/thread-spec.js
+++ b/lib/shared/threads/thread-spec.js
@@ -47,6 +47,10 @@
} from '../../types/message-types.js';
import type { RawTextMessageInfo } from '../../types/messages/text.js';
import type {
+ MemberInfoSansPermissions,
+ MinimallyEncodedThickMemberInfo,
+ RoleInfo,
+ ThreadCurrentUserInfo,
RawThreadInfo,
ThreadInfo,
} from '../../types/minimally-encoded-thread-permissions-types.js';
@@ -58,6 +62,7 @@
import type { ThreadType } from '../../types/thread-types-enum.js';
import type {
ChangeThreadSettingsPayload,
+ ClientDBThreadInfo,
LeaveThreadPayload,
UpdateThreadRequest,
} from '../../types/thread-types.js';
@@ -206,7 +211,11 @@
+dispatchActionPromise: DispatchActionPromise,
};
-export type ThreadProtocol = {
+export type ThreadProtocol<
+ RawThreadMemberType:
+ | MemberInfoSansPermissions
+ | MinimallyEncodedThickMemberInfo,
+> = {
+sendTextMessage: (
message: ProtocolSendTextMessageInput,
utils: SendTextMessageUtils,
@@ -260,6 +269,12 @@
input: ProtocolLeaveThreadInput,
utils: LeaveThreadUtils,
) => Promise<LeaveThreadResult>,
+ +convertClientDBThreadInfo: (
+ clientDBThreadInfo: ClientDBThreadInfo,
+ members: $ReadOnlyArray<RawThreadMemberType>,
+ roles: { +[id: string]: RoleInfo },
+ minimallyEncodedCurrentUser: ThreadCurrentUserInfo,
+ ) => RawThreadInfo,
+allowsDeletingSidebarSource: boolean,
+presentationDetails: {
+membershipChangesShownInThreadPreview: boolean,
@@ -283,8 +298,12 @@
+threadActivityUpdatedByDMActivityHandler: boolean,
};
-export type ThreadSpec = {
+export type ThreadSpec<
+ RawThreadMemberType:
+ | MemberInfoSansPermissions
+ | MinimallyEncodedThickMemberInfo,
+> = {
+traits: $ReadOnlySet<ThreadTrait>,
- +protocol: ThreadProtocol,
+ +protocol: ThreadProtocol<RawThreadMemberType>,
+threadLabel: string,
};
diff --git a/lib/shared/threads/thread-specs.js b/lib/shared/threads/thread-specs.js
--- a/lib/shared/threads/thread-specs.js
+++ b/lib/shared/threads/thread-specs.js
@@ -20,7 +20,7 @@
import { values } from '../../utils/objects.js';
export const threadSpecs: {
- +[ThreadType]: ThreadSpec,
+ +[ThreadType]: ThreadSpec<any>,
} = Object.freeze({
[threadTypes.SIDEBAR]: sidebarSpec,
[threadTypes.GENESIS_PERSONAL]: genesisPersonalSpec,
diff --git a/lib/utils/thread-ops-utils.js b/lib/utils/thread-ops-utils.js
--- a/lib/utils/thread-ops-utils.js
+++ b/lib/utils/thread-ops-utils.js
@@ -2,7 +2,6 @@
import invariant from 'invariant';
-import { assertWithValidator } from './validation-utils.js';
import {
memberInfoWithPermissionsValidator,
persistedRoleInfoValidator,
@@ -10,6 +9,7 @@
minimallyEncodedThickMemberInfoValidator,
memberInfoSansPermissionsValidator,
} from '../permissions/minimally-encoded-raw-thread-info-validators.js';
+import { threadSpecs } from '../shared/threads/thread-specs.js';
import type {
RawThreadInfo,
RoleInfo,
@@ -20,19 +20,13 @@
minimallyEncodeRoleInfo,
minimallyEncodeThreadCurrentUserInfo,
} from '../types/minimally-encoded-thread-permissions-types.js';
-import {
- assertThreadType,
- threadTypeIsThick,
- assertThinThreadType,
- assertThickThreadType,
-} from '../types/thread-types-enum.js';
+import { assertThreadType } from '../types/thread-types-enum.js';
import {
type ClientDBThreadInfo,
legacyMemberInfoValidator,
type LegacyRawThreadInfo,
clientLegacyRoleInfoValidator,
legacyThreadCurrentUserInfoValidator,
- threadTimestampsValidator,
} from '../types/thread-types.js';
function convertRawThreadInfoToClientDBThreadInfo(
@@ -99,72 +93,14 @@
? rawCurrentUser
: minimallyEncodeThreadCurrentUserInfo(rawCurrentUser);
- let rawThreadInfo: RawThreadInfo;
const threadType = assertThreadType(clientDBThreadInfo.type);
- if (threadTypeIsThick(threadType)) {
- const thickThreadType = assertThickThreadType(threadType);
- invariant(
- clientDBThreadInfo.timestamps,
- 'Thick thread info must contain the timestamps',
- );
- const threadTimestamps = assertWithValidator(
- JSON.parse(clientDBThreadInfo.timestamps),
- threadTimestampsValidator,
- );
- rawThreadInfo = {
- minimallyEncoded: true,
- thick: true,
- id: clientDBThreadInfo.id,
- type: thickThreadType,
- name: clientDBThreadInfo.name,
- description: clientDBThreadInfo.description,
- color: clientDBThreadInfo.color,
- creationTime: Number(clientDBThreadInfo.creationTime),
- parentThreadID: clientDBThreadInfo.parentThreadID,
- containingThreadID: clientDBThreadInfo.containingThreadID,
- members: minimallyEncodedMembers,
- roles: minimallyEncodedRoles,
- currentUser: minimallyEncodedCurrentUser,
- repliesCount: clientDBThreadInfo.repliesCount,
- pinnedCount: clientDBThreadInfo.pinnedCount,
- timestamps: threadTimestamps,
- };
- } else {
- const thinThreadType = assertThinThreadType(threadType);
- rawThreadInfo = {
- minimallyEncoded: true,
- id: clientDBThreadInfo.id,
- type: thinThreadType,
- name: clientDBThreadInfo.name,
- description: clientDBThreadInfo.description,
- color: clientDBThreadInfo.color,
- creationTime: Number(clientDBThreadInfo.creationTime),
- parentThreadID: clientDBThreadInfo.parentThreadID,
- containingThreadID: clientDBThreadInfo.containingThreadID,
- community: clientDBThreadInfo.community,
- members: minimallyEncodedMembers,
- roles: minimallyEncodedRoles,
- currentUser: minimallyEncodedCurrentUser,
- repliesCount: clientDBThreadInfo.repliesCount,
- pinnedCount: clientDBThreadInfo.pinnedCount,
- };
- }
- if (clientDBThreadInfo.sourceMessageID) {
- rawThreadInfo = {
- ...rawThreadInfo,
- sourceMessageID: clientDBThreadInfo.sourceMessageID,
- };
- }
-
- if (clientDBThreadInfo.avatar) {
- rawThreadInfo = {
- ...rawThreadInfo,
- avatar: JSON.parse(clientDBThreadInfo.avatar),
- };
- }
-
- return rawThreadInfo;
+ return threadSpecs[threadType].protocol.convertClientDBThreadInfo(
+ clientDBThreadInfo,
+ minimallyEncodedMembers,
+ minimallyEncodedRoles,
+ minimallyEncodedCurrentUser,
+ );
}
// WARNING: Do not consume or delete this function!

File Metadata

Mime Type
text/plain
Expires
Wed, Jan 14, 3:19 PM (6 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5930846
Default Alt Text
D14641.1768403996.diff (70 KB)

Event Timeline