Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F33032169
D14641.1768403996.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
70 KB
Referenced Files
None
Subscribers
None
D14641.1768403996.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D14641: [lib] Move converting DB threads to a spec
Attached
Detach File
Event Timeline
Log In to Comment