diff --git a/lib/types/messages/change-role.js b/lib/types/messages/change-role.js index 1c2a115d6..13972b4fa 100644 --- a/lib/types/messages/change-role.js +++ b/lib/types/messages/change-role.js @@ -1,45 +1,45 @@ // @flow import t, { type TInterface } from 'tcomb'; import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type ChangeRoleMessageData = { +type: 6, +threadID: string, +creatorID: string, +time: number, +userIDs: string[], +newRole: string, +roleName?: string, // Older clients will not have this field }; -export type RawChangeRoleMessageInfo = { +export type RawChangeRoleMessageInfo = $ReadOnly<{ ...ChangeRoleMessageData, +id: string, -}; +}>; export const rawChangeRoleMessageInfoValidator: TInterface = tShape({ type: tNumber(messageTypes.CHANGE_ROLE), threadID: tID, creatorID: t.String, time: t.Number, userIDs: t.list(t.String), newRole: tID, id: tID, roleName: t.maybe(t.String), }); export type ChangeRoleMessageInfo = { +type: 6, +id: string, +threadID: string, +creator: RelativeUserInfo, +time: number, +members: RelativeUserInfo[], +newRole: string, +roleName?: string, // Older clients will not have this field }; diff --git a/lib/types/messages/edit.js b/lib/types/messages/edit.js index fb3860d14..5f21565bb 100644 --- a/lib/types/messages/edit.js +++ b/lib/types/messages/edit.js @@ -1,42 +1,42 @@ // @flow import t, { type TInterface } from 'tcomb'; import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type EditMessageData = { +type: 20, +threadID: string, +creatorID: string, +time: number, +targetMessageID: string, +text: string, }; -export type RawEditMessageInfo = { +export type RawEditMessageInfo = $ReadOnly<{ ...EditMessageData, +id: string, -}; +}>; export const rawEditMessageInfoValidator: TInterface = tShape({ type: tNumber(messageTypes.EDIT_MESSAGE), threadID: tID, creatorID: t.String, time: t.Number, targetMessageID: tID, text: t.String, id: tID, }); export type EditMessageInfo = { +type: 20, +id: string, +threadID: string, +creator: RelativeUserInfo, +time: number, // millisecond timestamp +targetMessageID: string, +text: string, }; diff --git a/lib/types/messages/media.js b/lib/types/messages/media.js index c7bb281c2..6df679c23 100644 --- a/lib/types/messages/media.js +++ b/lib/types/messages/media.js @@ -1,96 +1,96 @@ // @flow import t, { type TInterface } from 'tcomb'; import { tShape, tNumber, tID } from '../../utils/validation-utils.js'; import { type Media, mediaValidator } from '../media-types.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; type MediaSharedBase = { +type: 15, +localID?: string, // for optimistic creations. included by new clients +threadID: string, +creatorID: string, +time: number, +media: $ReadOnlyArray, }; -export type MediaMessageData = { +export type MediaMessageData = $ReadOnly<{ ...MediaSharedBase, +sidebarCreation?: boolean, -}; +}>; -export type RawMediaMessageInfo = { +export type RawMediaMessageInfo = $ReadOnly<{ ...MediaSharedBase, +id?: string, // null if local copy without ID yet -}; +}>; export const rawMediaMessageInfoValidator: TInterface = tShape({ type: tNumber(messageTypes.MULTIMEDIA), localID: t.maybe(t.String), threadID: tID, creatorID: t.String, time: t.Number, media: t.list(mediaValidator), id: t.maybe(tID), }); export type MediaMessageInfo = { +type: 15, +id?: string, // null if local copy without ID yet +localID?: string, // for optimistic creations +threadID: string, +creator: RelativeUserInfo, +time: number, // millisecond timestamp +media: $ReadOnlyArray, }; export type PhotoMessageServerDBContent = { +type: 'photo', +uploadID: string, }; export type VideoMessageServerDBContent = { +type: 'video', +uploadID: string, +thumbnailUploadID: string, }; export type MediaMessageServerDBContent = | PhotoMessageServerDBContent | VideoMessageServerDBContent; function getUploadIDsFromMediaMessageServerDBContents( mediaMessageContents: $ReadOnlyArray, ): $ReadOnlyArray { const uploadIDs: string[] = []; for (const mediaContent of mediaMessageContents) { uploadIDs.push(mediaContent.uploadID); if (mediaContent.type === 'video') { uploadIDs.push(mediaContent.thumbnailUploadID); } } return uploadIDs; } function getMediaMessageServerDBContentsFromMedia( media: $ReadOnlyArray, ): $ReadOnlyArray { return media.map(m => { if (m.type === 'photo' || m.type === 'encrypted_photo') { return { type: 'photo', uploadID: m.id }; } else if (m.type === 'video' || m.type === 'encrypted_video') { return { type: 'video', uploadID: m.id, thumbnailUploadID: m.thumbnailID, }; } throw new Error(`Unexpected media type: ${m.type}`); }); } export { getUploadIDsFromMediaMessageServerDBContents, getMediaMessageServerDBContentsFromMedia, }; diff --git a/lib/types/messages/reaction.js b/lib/types/messages/reaction.js index f069ea860..7950f0528 100644 --- a/lib/types/messages/reaction.js +++ b/lib/types/messages/reaction.js @@ -1,48 +1,48 @@ // @flow import t, { type TInterface } from 'tcomb'; import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type ReactionMessageData = { +type: 19, +localID?: string, // for optimistic creations. included by new clients +threadID: string, +creatorID: string, +time: number, +targetMessageID: string, +reaction: string, +action: 'add_reaction' | 'remove_reaction', }; -export type RawReactionMessageInfo = { +export type RawReactionMessageInfo = $ReadOnly<{ ...ReactionMessageData, - id?: string, // null if local copy without ID yet -}; + +id?: string, // null if local copy without ID yet +}>; export const rawReactionMessageInfoValidator: TInterface = tShape({ type: tNumber(messageTypes.REACTION), localID: t.maybe(t.String), threadID: tID, creatorID: t.String, time: t.Number, targetMessageID: tID, reaction: t.String, action: t.enums.of(['add_reaction', 'remove_reaction']), id: t.maybe(tID), }); export type ReactionMessageInfo = { +type: 19, +id?: string, // null if local copy without ID yet +localID?: string, // for optimistic creations +threadID: string, +creator: RelativeUserInfo, +time: number, +targetMessageID: string, +reaction: string, +action: 'add_reaction' | 'remove_reaction', }; diff --git a/lib/types/messages/toggle-pin.js b/lib/types/messages/toggle-pin.js index b3ffe7666..100c2118b 100644 --- a/lib/types/messages/toggle-pin.js +++ b/lib/types/messages/toggle-pin.js @@ -1,45 +1,45 @@ // @flow import t, { type TInterface } from 'tcomb'; import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type TogglePinMessageData = { +type: 21, +threadID: string, +targetMessageID: string, +action: 'pin' | 'unpin', +pinnedContent: string, +creatorID: string, +time: number, }; -export type RawTogglePinMessageInfo = { +export type RawTogglePinMessageInfo = $ReadOnly<{ ...TogglePinMessageData, +id: string, -}; +}>; export const rawTogglePinMessageInfoValidator: TInterface = tShape({ type: tNumber(messageTypes.TOGGLE_PIN), threadID: tID, targetMessageID: tID, action: t.enums.of(['pin', 'unpin']), pinnedContent: t.String, creatorID: t.String, time: t.Number, id: tID, }); export type TogglePinMessageInfo = { +type: 21, +id: string, +threadID: string, +targetMessageID: string, +action: 'pin' | 'unpin', +pinnedContent: string, +creator: RelativeUserInfo, +time: number, }; diff --git a/lib/types/messages/unsupported.js b/lib/types/messages/unsupported.js index a89053b3a..86069acf0 100644 --- a/lib/types/messages/unsupported.js +++ b/lib/types/messages/unsupported.js @@ -1,41 +1,87 @@ // @flow import t, { type TInterface } from 'tcomb'; +import { + rawChangeRoleMessageInfoValidator, + type RawChangeRoleMessageInfo, +} from './change-role.js'; +import { + rawEditMessageInfoValidator, + type RawEditMessageInfo, +} from './edit.js'; +import { + rawMediaMessageInfoValidator, + type RawMediaMessageInfo, +} from './media.js'; +import { + rawReactionMessageInfoValidator, + type RawReactionMessageInfo, +} from './reaction.js'; +import { + rawTogglePinMessageInfoValidator, + type RawTogglePinMessageInfo, +} from './toggle-pin.js'; +import { + rawUpdateFarcasterRelationshipMessageInfoValidator, + type RawUpdateFarcasterRelationshipMessageInfo, +} from './update-relationship.js'; import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type RawUnsupportedMessageInfo = { type: 13, id: string, threadID: string, creatorID: string, time: number, robotext: string, dontPrefixCreator?: boolean, - unsupportedMessageInfo: Object, + unsupportedMessageInfo: + | RawUpdateFarcasterRelationshipMessageInfo + | RawChangeRoleMessageInfo + | RawEditMessageInfo + | RawMediaMessageInfo + | RawReactionMessageInfo + | RawTogglePinMessageInfo, }; export const rawUnsupportedMessageInfoValidator: TInterface = tShape({ type: tNumber(messageTypes.UNSUPPORTED), id: tID, threadID: tID, creatorID: t.String, time: t.Number, robotext: t.String, dontPrefixCreator: t.maybe(t.Boolean), - unsupportedMessageInfo: t.Object, + unsupportedMessageInfo: t.union([ + // We include these validators here to make sure that the keyserver does + // ID conversion on unsupportedMessageInfo when it's one of these types + rawUpdateFarcasterRelationshipMessageInfoValidator, + rawChangeRoleMessageInfoValidator, + rawEditMessageInfoValidator, + rawMediaMessageInfoValidator, + rawReactionMessageInfoValidator, + rawTogglePinMessageInfoValidator, + t.Object, + ]), }); export type UnsupportedMessageInfo = { type: 13, id: string, threadID: string, creator: RelativeUserInfo, time: number, robotext: string, dontPrefixCreator?: boolean, - unsupportedMessageInfo: Object, + unsupportedMessageInfo: + | RawUpdateFarcasterRelationshipMessageInfo + | RawChangeRoleMessageInfo + | RawEditMessageInfo + | RawMediaMessageInfo + | RawReactionMessageInfo + | RawTogglePinMessageInfo, }; diff --git a/lib/types/messages/update-relationship.js b/lib/types/messages/update-relationship.js index 55f8d19f0..c48d1efd3 100644 --- a/lib/types/messages/update-relationship.js +++ b/lib/types/messages/update-relationship.js @@ -1,98 +1,107 @@ // @flow import t, { type TInterface, type TUnion } from 'tcomb'; import { tID, tNumber, tShape, tString } from '../../utils/validation-utils.js'; import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type TraditionalRelationshipOperation = | 'request_sent' | 'request_accepted'; export type FarcasterRelationshipOperation = 'farcaster_mutual'; export type UpdateTraditionalRelationshipMessageData = { +type: 22, +threadID: string, +creatorID: string, +targetID: string, +time: number, +operation: TraditionalRelationshipOperation, }; export type UpdateFarcasterRelationshipMessageData = { +type: 22, +threadID: string, +creatorID: string, +creatorFID: string, +targetID: string, +targetFID: string, +time: number, +operation: FarcasterRelationshipOperation, }; export type UpdateRelationshipMessageData = | UpdateTraditionalRelationshipMessageData | UpdateFarcasterRelationshipMessageData; -export type RawUpdateRelationshipMessageInfo = { - ...UpdateRelationshipMessageData, - id: string, -}; +export type RawUpdateTraditionalRelationshipMessageInfo = $ReadOnly<{ + ...UpdateTraditionalRelationshipMessageData, + +id: string, +}>; + +export type RawUpdateFarcasterRelationshipMessageInfo = $ReadOnly<{ + ...UpdateFarcasterRelationshipMessageData, + +id: string, +}>; + +export type RawUpdateRelationshipMessageInfo = + | RawUpdateTraditionalRelationshipMessageInfo + | RawUpdateFarcasterRelationshipMessageInfo; export const rawUpdateTraditionalRelationshipMessageInfoValidator: TInterface = tShape({ id: tID, type: tNumber(messageTypes.UPDATE_RELATIONSHIP), threadID: tID, creatorID: t.String, targetID: t.String, time: t.Number, operation: t.enums.of(['request_sent', 'request_accepted']), }); export const rawUpdateFarcasterRelationshipMessageInfoValidator: TInterface = tShape({ id: tID, type: tNumber(messageTypes.UPDATE_RELATIONSHIP), threadID: tID, creatorID: t.String, creatorFID: t.String, targetID: t.String, targetFID: t.String, time: t.Number, operation: tString('farcaster_mutual'), }); export const rawUpdateRelationshipMessageInfoValidator: TUnion = t.union([ rawUpdateTraditionalRelationshipMessageInfoValidator, rawUpdateFarcasterRelationshipMessageInfoValidator, ]); export type UpdateTraditionalRelationshipMessageInfo = { +type: 22, +id: string, +threadID: string, +creator: RelativeUserInfo, +target: RelativeUserInfo, +time: number, +operation: TraditionalRelationshipOperation, }; export type UpdateFarcasterRelationshipMessageInfo = { +type: 22, +id: string, +threadID: string, +creator: RelativeUserInfo, +creatorFID: string, +target: RelativeUserInfo, +targetFID: string, +time: number, +operation: FarcasterRelationshipOperation, }; export type UpdateRelationshipMessageInfo = | UpdateTraditionalRelationshipMessageInfo | UpdateFarcasterRelationshipMessageInfo;