diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js --- a/lib/types/dm-ops.js +++ b/lib/types/dm-ops.js @@ -25,7 +25,14 @@ } from './thread-types.js'; import type { ClientUpdateInfo } from './update-types.js'; import { values } from '../utils/objects.js'; -import { tColor, tShape, tString, tUserID } from '../utils/validation-utils.js'; +import { + tColor, + tRegex, + tShape, + tString, + tUserID, + uuidRegex, +} from '../utils/validation-utils.js'; export const dmOperationTypes = Object.freeze({ CREATE_THREAD: 'create_thread', @@ -48,6 +55,15 @@ }); export type DMOperationType = $Values; +const thickIDRegex = new RegExp(`^${uuidRegex}$`); +const tThickID = tRegex(thickIDRegex); + +// In CHANGE_THREAD_SETTINGS operation we're generating message IDs +// based on the prefix that is tThickID. A message with the generated ID +// can be used as a target message of the edit, reaction, or a sidebar. +const thickTargetMessageIDRegex = new RegExp(`^${uuidRegex}(?:/\\w+)?$`); +const tThickTargetMessageID = tRegex(thickTargetMessageIDRegex); + type MemberIDWithSubscription = { +id: string, +subscription: ThreadSubscription, @@ -78,20 +94,20 @@ }; export const createThickRawThreadInfoInputValidator: TInterface = tShape({ - threadID: t.String, + threadID: tThickID, threadType: thickThreadTypeValidator, creationTime: t.Number, - parentThreadID: t.maybe(t.String), + parentThreadID: t.maybe(tThickID), allMemberIDsWithSubscriptions: t.list(memberIDWithSubscriptionValidator), - roleID: t.String, + roleID: tThickID, unread: t.Boolean, timestamps: threadTimestampsValidator, name: t.maybe(t.String), avatar: t.maybe(clientAvatarValidator), description: t.maybe(t.String), color: t.maybe(t.String), - containingThreadID: t.maybe(t.String), - sourceMessageID: t.maybe(t.String), + containingThreadID: t.maybe(tThickID), + sourceMessageID: t.maybe(tThickTargetMessageID), repliesCount: t.maybe(t.Number), pinnedCount: t.maybe(t.Number), }); @@ -109,13 +125,13 @@ export const dmCreateThreadOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.CREATE_THREAD), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, threadType: t.enums.of(values(nonSidebarThickThreadTypes)), memberIDs: t.list(tUserID), - roleID: t.String, - newMessageID: t.String, + roleID: tThickID, + newMessageID: tThickID, }); export type DMCreateSidebarOperation = { @@ -133,15 +149,15 @@ export const dmCreateSidebarOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.CREATE_SIDEBAR), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, - parentThreadID: t.String, + parentThreadID: tThickID, memberIDs: t.list(tUserID), - sourceMessageID: t.String, - roleID: t.String, - newSidebarSourceMessageID: t.String, - newCreateSidebarMessageID: t.String, + sourceMessageID: tThickTargetMessageID, + roleID: tThickID, + newSidebarSourceMessageID: tThickID, + newCreateSidebarMessageID: tThickID, }); export type DMSendTextMessageOperation = { @@ -155,10 +171,10 @@ export const dmSendTextMessageOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.SEND_TEXT_MESSAGE), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, - messageID: t.String, + messageID: tThickID, text: t.String, }); @@ -173,10 +189,10 @@ export const dmSendMultimediaMessageOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.SEND_MULTIMEDIA_MESSAGE), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, - messageID: t.String, + messageID: tThickID, media: t.list(mediaValidator), }); @@ -193,11 +209,11 @@ export const dmSendReactionMessageOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.SEND_REACTION_MESSAGE), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, - messageID: t.String, - targetMessageID: t.String, + messageID: tThickID, + targetMessageID: tThickTargetMessageID, reaction: t.String, action: t.enums.of(['add_reaction', 'remove_reaction']), }); @@ -214,11 +230,11 @@ export const dmSendEditMessageOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.SEND_EDIT_MESSAGE), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, - messageID: t.String, - targetMessageID: t.String, + messageID: tThickID, + targetMessageID: tThickTargetMessageID, text: t.String, }); @@ -242,8 +258,8 @@ export const dmAddMembersOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.ADD_MEMBERS), - threadID: t.String, - messageID: t.String, + threadID: tThickID, + messageID: tThickID, ...dmAddMembersBaseValidatorShape, }); @@ -256,7 +272,7 @@ export const dmAddViewerToThreadMembersValidator: TInterface = tShape({ type: tString(dmOperationTypes.ADD_VIEWER_TO_THREAD_MEMBERS), - messageID: t.maybe(t.String), + messageID: t.maybe(tThickID), existingThreadDetails: createThickRawThreadInfoInputValidator, ...dmAddMembersBaseValidatorShape, }); @@ -273,7 +289,7 @@ type: tString(dmOperationTypes.JOIN_THREAD), joinerID: tUserID, time: t.Number, - messageID: t.String, + messageID: tThickID, existingThreadDetails: createThickRawThreadInfoInputValidator, }); @@ -289,8 +305,8 @@ type: tString(dmOperationTypes.LEAVE_THREAD), editorID: tUserID, time: t.Number, - messageID: t.String, - threadID: t.String, + messageID: tThickID, + threadID: tThickID, }); export type DMThreadSettingsChanges = { @@ -311,7 +327,7 @@ export const dmChangeThreadSettingsOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.CHANGE_THREAD_SETTINGS), - threadID: t.String, + threadID: tThickID, editorID: tUserID, time: t.Number, changes: tShape({ @@ -320,7 +336,7 @@ color: t.maybe(tColor), avatar: t.maybe(clientAvatarValidator), }), - messageIDsPrefix: t.String, + messageIDsPrefix: tThickID, }); export type DMChangeThreadSubscriptionOperation = { @@ -334,7 +350,7 @@ tShape({ type: tString(dmOperationTypes.CHANGE_THREAD_SUBSCRIPTION), time: t.Number, - threadID: t.String, + threadID: tThickID, creatorID: tUserID, subscription: threadSubscriptionValidator, }); @@ -350,7 +366,7 @@ tShape({ type: tString(dmOperationTypes.CHANGE_THREAD_READ_STATUS), time: t.Number, - threadID: t.String, + threadID: tThickID, creatorID: tUserID, unread: t.Boolean, }); @@ -372,13 +388,13 @@ export const dmCreateEntryOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.CREATE_ENTRY), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, - entryID: t.String, + entryID: tThickID, entryDate: t.String, text: t.String, - messageID: t.String, + messageID: tThickID, }); export type DMDeleteEntryOperation = { @@ -395,14 +411,14 @@ export const dmDeleteEntryOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.DELETE_ENTRY), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, creationTime: t.Number, - entryID: t.String, + entryID: tThickID, entryDate: t.String, prevText: t.String, - messageID: t.String, + messageID: tThickID, }); export type DMEditEntryOperation = { @@ -419,14 +435,14 @@ export const dmEditEntryOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.EDIT_ENTRY), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, creationTime: t.Number, time: t.Number, - entryID: t.String, + entryID: tThickID, entryDate: t.String, text: t.String, - messageID: t.String, + messageID: tThickID, }); export type DMUpdateRelationshipOperation = { @@ -441,7 +457,7 @@ export const dmUpdateRelationshipOperationValidator: TInterface = tShape({ type: tString(dmOperationTypes.UPDATE_RELATIONSHIP), - threadID: t.String, + threadID: tThickID, creatorID: tUserID, time: t.Number, operation: t.enums.of([ @@ -450,7 +466,7 @@ 'farcaster_mutual', ]), targetUserID: tUserID, - messageID: t.String, + messageID: tThickID, }); export type DMOperation = diff --git a/lib/utils/validation-utils.js b/lib/utils/validation-utils.js --- a/lib/utils/validation-utils.js +++ b/lib/utils/validation-utils.js @@ -147,6 +147,7 @@ tMediaMessageMedia, assertWithValidator, ashoatKeyserverID, + uuidRegex, idSchemaRegex, pendingSidebarURLPrefix, pendingThickSidebarURLPrefix,