Skip to content

Commit

Permalink
feat(lib): add custom content paths
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-suwala committed Feb 27, 2024
1 parent 36701bc commit cea89e1
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 37 deletions.
39 changes: 39 additions & 0 deletions lib/src/default-values.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { MessageActionType, MessageType, TextMessageContent } from "./types"
import { Message } from "./entities/message"

export function defaultGetMessagePublishBody(messageBody: TextMessageContent) {
return {
type: messageBody.type,
text: messageBody.text,
files: messageBody.files,
}
}

export function defaultGetMessageResponseBody<MessageBody extends object = TextMessageContent>(
messageBody: MessageBody
) {
if ("type" in messageBody && "text" in messageBody && "files" in messageBody) {
return {
type: MessageType.TEXT,
text: typeof messageBody.text === "string" ? messageBody.text : "UNKNOWN",
files: Array.isArray(messageBody.files) ? messageBody.files : [],
}
}
return {
type: MessageType.TEXT,
text: "UNKNOWN",
files: [],
}
}

export function defaultGetMessageDisplayContent(message: Message, editActionName: string) {
const edits = message.actions?.[editActionName]
if (!edits) return message.content.text || ""
const flatEdits = Object.entries(edits).map(([k, v]) => ({ value: k, ...v[0] }))
const lastEdit = flatEdits.reduce((a, b) => (a.actionTimetoken > b.actionTimetoken ? a : b))

return lastEdit.value
}

export const defaultEditActionName = MessageActionType.EDITED
export const defaultDeleteActionName = MessageActionType.DELETED
33 changes: 23 additions & 10 deletions lib/src/entities/channel.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import PubNub, {
GetChannelMembersParameters,
MessageEvent,
ObjectCustom,
GetChannelMembersParameters,
SetMembershipsParameters,
ChannelMetadataObject,
} from "pubnub"
import { Chat } from "./chat"
import { Message } from "./message"
import { Event } from "./event"
import {
SendTextOptionParams,
DeleteParameters,
ChannelDTOParams,
ChannelType,
DeleteParameters,
MessageDraftConfig,
MessageType,
SendTextOptionParams,
TextMessageContent,
ChannelType,
} from "../types"
import { ExponentialRateLimiter } from "../rate-limiter"
import { Membership } from "./membership"
Expand All @@ -24,6 +23,7 @@ import { MessageElementsUtils } from "../message-elements-utils"
import { MessageDraft } from "./message-draft"
import { getErrorProxiedEntity } from "../error-logging"
import { INTERNAL_MODERATION_PREFIX } from "../constants"
import { defaultGetMessagePublishBody } from "../default-values"

export type ChannelFields = Pick<
Channel,
Expand Down Expand Up @@ -65,7 +65,7 @@ export class Channel {
}

/** @internal */
static fromDTO(chat: Chat, params: ChannelDTOParams) {
static fromDTO(chat: Chat, params: ChannelDTOParams): Channel {
const data = {
id: params.id,
name: params.name || undefined,
Expand Down Expand Up @@ -194,10 +194,23 @@ export class Channel {
}
}

const message: TextMessageContent = {
type: MessageType.TEXT,
text,
...(filesData.length && { files: filesData }),
// const message: TextMessageContent = {
// type: MessageType.TEXT,
// text,
// ...(filesData.length && { files: filesData }),
// ...this.getPushPayload(text),
// }
const getMessagePublishBody =
this.chat.config.customPayloads.getMessagePublishBody || defaultGetMessagePublishBody
const message = {
...getMessagePublishBody(
{
type: MessageType.TEXT,
text,
files: filesData,
},
this
),
...this.getPushPayload(text),
}

Expand Down
46 changes: 44 additions & 2 deletions lib/src/entities/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { MessageElementsUtils } from "../message-elements-utils"
import { getErrorProxiedEntity, ErrorLogger } from "../error-logging"
import { cyrb53a } from "../hash"
import { uuidv4 } from "../uuidv4"
import { defaultEditActionName, defaultDeleteActionName } from "../default-values"

export type ChatConfig = {
saveDebugLog: boolean
Expand All @@ -39,6 +40,15 @@ export type ChatConfig = {
[key in ChannelType]: number
}
errorLogger?: ErrorLoggerImplementation
customPayloads: {
getMessagePublishBody?: (m: TextMessageContent, channel: Channel) => any
getMessageResponseBody?: (m: any) => TextMessageContent
getMessageDisplayContent?: (m: Message) => string
editMessage?: (m: Message, newText: string) => Promise<Message>
editMessageActionName?: string
deleteMessage?: (m: Message) => Promise<boolean>
deleteMessageActionName?: string
}
}

type ChatConstructor = Partial<ChatConfig> & PubNub.PubnubConfig
Expand All @@ -57,6 +67,10 @@ export class Chat {
private subscriptions: { [channel: string]: Set<string> }
/** @internal */
errorLogger: ErrorLogger
/** @internal */
public editMessageActionName: string
/** @internal */
public deleteMessageActionName: string

/** @internal */
private constructor(params: ChatConstructor) {
Expand All @@ -69,10 +83,14 @@ export class Chat {
rateLimitFactor,
rateLimitPerChannel,
errorLogger,
customPayloads,
...pubnubConfig
} = params

this.errorLogger = new ErrorLogger(errorLogger)
this.editMessageActionName = customPayloads?.editMessageActionName || defaultEditActionName
this.deleteMessageActionName =
customPayloads?.deleteMessageActionName || defaultDeleteActionName

try {
if (storeUserActivityInterval && storeUserActivityInterval < 60000) {
Expand All @@ -87,6 +105,23 @@ export class Chat {
throw error
}

try {
if (customPayloads?.deleteMessageActionName && customPayloads?.deleteMessage) {
throw "Both 'deleteMessageActionName' and 'deleteMessage' are defined. Choose just one of them instead."
}
} catch (error) {
this.errorLogger.setItem("deleteMessageConfigError", error, arguments)
throw error
}
try {
if (customPayloads?.editMessageActionName && customPayloads?.editMessage) {
throw "Both 'editMessageActionName' and 'editMessage' are defined. Choose just one of them instead."
}
} catch (error) {
this.errorLogger.setItem("editMessageConfigError", error, arguments)
throw error
}

/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
const pubnub = new PubNub(pubnubConfig) as any
pubnub._config._addPnsdkSuffix("chat-sdk", `__PLATFORM__/__VERSION__`)
Expand Down Expand Up @@ -116,7 +151,14 @@ export class Chat {
public: 0,
unknown: 0,
},
}
customPayloads: {
getMessagePublishBody: customPayloads?.getMessagePublishBody,
getMessageResponseBody: customPayloads?.getMessageResponseBody,
getMessageDisplayContent: customPayloads?.getMessageDisplayContent,
editMessage: customPayloads?.editMessage,
deleteMessage: customPayloads?.deleteMessage,
},
} as ChatConfig
}

static async init(params: ChatConstructor) {
Expand Down Expand Up @@ -659,7 +701,7 @@ export class Chat {
originalPublisher: message.userId,
originalChannelId: message.channelId,
}
this.publish({ message: message.content, channel, meta })
return this.publish({ message: message.content, channel, meta })
}

/** @internal */
Expand Down
6 changes: 3 additions & 3 deletions lib/src/entities/event.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MessageEvent, FetchMessagesResponse } from "pubnub"
import { Chat } from "./chat"
import { EventPayloads, EventType } from "../types"
import { EventPayloads, EventType, TextMessageContent } from "../types"
import { getErrorProxiedEntity } from "../error-logging"

export type EventFields<T extends EventType> = Pick<
Expand Down Expand Up @@ -28,15 +28,15 @@ export class Event<T extends EventType> {
}

/** @internal */
static fromDTO(
static fromDTO<T extends EventType>(
chat: Chat,
params:
| Pick<MessageEvent, "timetoken" | "message" | "channel" | "publisher">
| Pick<
FetchMessagesResponse["channels"][string][number],
"timetoken" | "message" | "channel" | "uuid"
>
) {
): Event<T> {
const { type, ...payload } = params.message
const data = {
timetoken: String(params.timetoken),
Expand Down
55 changes: 36 additions & 19 deletions lib/src/entities/message.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Chat } from "./chat"
import PubNub from "pubnub"
import {
MessageActionType,
MessageActions,
DeleteParameters,
MessageActions,
MessageDTOParams,
MessageType,
TextMessageContent,
MessageActionType,
} from "../types"
import { INTERNAL_ADMIN_CHANNEL } from "../constants"
import { getErrorProxiedEntity } from "../error-logging"
import { MessageElementsUtils } from "../message-elements-utils"
import { defaultGetMessageDisplayContent, defaultGetMessageResponseBody } from "../default-values"

export type MessageFields = Pick<
Message,
Expand Down Expand Up @@ -88,17 +90,20 @@ export class Message {
}

/** @internal */
static fromDTO(chat: Chat, params: MessageDTOParams) {
static fromDTO(chat: Chat, params: MessageDTOParams): Message {
const getMessageResponseBody =
chat.config.customPayloads.getMessageResponseBody || defaultGetMessageResponseBody

const data = {
timetoken: String(params.timetoken),
content:
typeof params.message === "string"
? {
type: "text",
? getMessageResponseBody({
type: MessageType.TEXT,
text: params.message,
files: [],
}
: params.message,
})
: getMessageResponseBody(params.message),
channelId: params.channel,
userId: "publisher" in params ? params.publisher : params.uuid || "unknown-user",
actions: "actions" in params ? params.actions : undefined,
Expand Down Expand Up @@ -182,13 +187,16 @@ export class Message {
* Message text
*/
get text() {
const type = MessageActionType.EDITED
const edits = this.actions?.[type]
if (!edits) return this.content.text || ""
const flatEdits = Object.entries(edits).map(([k, v]) => ({ value: k, ...v[0] }))
const lastEdit = flatEdits.reduce((a, b) => (a.actionTimetoken > b.actionTimetoken ? a : b))

return lastEdit.value
// const type = MessageActionType.EDITED
// const edits = this.actions?.[type]
// if (!edits) return this.content.text || ""
// const flatEdits = Object.entries(edits).map(([k, v]) => ({ value: k, ...v[0] }))
// const lastEdit = flatEdits.reduce((a, b) => (a.actionTimetoken > b.actionTimetoken ? a : b))
//
// return lastEdit.value
const getMessageDisplayContent =
this.chat.config.customPayloads.getMessageDisplayContent || defaultGetMessageDisplayContent
return getMessageDisplayContent(this, this.chat.editMessageActionName)
}

getMessageElements() {
Expand All @@ -210,7 +218,11 @@ export class Message {
}

async editText(newText: string) {
const type = MessageActionType.EDITED
if (this.chat.config.customPayloads.editMessage) {
return this.chat.config.customPayloads.editMessage(this, newText)
}

const type = this.chat.editMessageActionName
try {
const { data } = await this.chat.sdk.addMessageAction({
channel: this.channelId,
Expand All @@ -228,13 +240,17 @@ export class Message {
* Deletions
*/
get deleted() {
const type = MessageActionType.DELETED
const type = this.chat.deleteMessageActionName
return !!this.actions?.[type] && !!this.actions?.[type][type].length
}

async delete(params: DeleteParameters & { preserveFiles?: boolean } = {}) {
if (this.chat.config.customPayloads.deleteMessage) {
return this.chat.config.customPayloads.deleteMessage(this)
}

const { soft } = params
const type = MessageActionType.DELETED
const type = this.chat.deleteMessageActionName
try {
if (soft) {
const { data } = await this.chat.sdk.addMessageAction({
Expand Down Expand Up @@ -273,7 +289,8 @@ export class Message {
console.warn("This message has not been deleted")
return
}
const deletedActions = this.actions?.[MessageActionType.DELETED]?.[MessageActionType.DELETED]
const deletedActions =
this.actions?.[this.chat.deleteMessageActionName]?.[this.chat.deleteMessageActionName]
if (!deletedActions) {
console.warn("Malformed data", deletedActions)
return
Expand All @@ -299,7 +316,7 @@ export class Message {
])

let allActions = this.actions || {}
delete allActions[MessageActionType.DELETED]
delete allActions[this.chat.deleteMessageActionName]

for (let i = 0; i < data.length; i++) {
const actions = this.assignAction(data[i])
Expand Down
2 changes: 1 addition & 1 deletion lib/src/entities/thread-channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ThreadChannel extends Channel {
}

/** @internal */
static override fromDTO(chat: Chat, params: ThreadChannelDTOParams) {
static override fromDTO(chat: Chat, params: ThreadChannelDTOParams): ThreadChannel {
const data = {
id: params.id,
parentChannelId: params.parentChannelId,
Expand Down
4 changes: 2 additions & 2 deletions lib/src/entities/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import PubNub, { UUIDMetadataObject, ObjectCustom, GetMembershipsParametersv2 } from "pubnub"
import { Chat } from "./chat"
import { DeleteParameters, OptionalAllBut } from "../types"
import { DeleteParameters, OptionalAllBut, TextMessageContent } from "../types"
import { Channel } from "./channel"
import { Membership } from "./membership"
import { INTERNAL_ADMIN_CHANNEL, INTERNAL_MODERATION_PREFIX } from "../constants"
Expand Down Expand Up @@ -40,7 +40,7 @@ export class User {
type?: string | null
})
| UUIDMetadataObject<ObjectCustom>
) {
): User {
const data = {
id: params.id,
name: params.name || undefined,
Expand Down
Loading

0 comments on commit cea89e1

Please sign in to comment.