Skip to content

Commit 090daf7

Browse files
committed
fix: add attachments support
1 parent 49d4aad commit 090daf7

File tree

7 files changed

+303
-16
lines changed

7 files changed

+303
-16
lines changed

packages/common/src/adapter.interface.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,10 @@ export interface AdapterInterface<
301301
* @param message
302302
* @param options Options for creating the container.
303303
*/
304-
createContainer: (message: Message, options: CreateContainerOptions) => C;
304+
createContainer: (
305+
message: Message,
306+
options: CreateContainerOptions,
307+
) => Promise<C>;
305308

306309
/**
307310
* Authorizes the request.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
* Add more attachment types as needed.
3+
*/
4+
export enum AttachmentType {
5+
/**
6+
* An image attachment.
7+
*/
8+
Image = "image",
9+
/**
10+
* A video attachment.
11+
*/
12+
Video = "video",
13+
/**
14+
* An audio attachment.
15+
*/
16+
Audio = "audio",
17+
/**
18+
* A file attachment.
19+
*/
20+
File = "file",
21+
/**
22+
* A user recorded voice attachment.
23+
*/
24+
Voice = "voice",
25+
/**
26+
* A sticker attachment.
27+
*/
28+
Sticker = "sticker",
29+
/**
30+
* A contact attachment.
31+
*/
32+
Contact = "contact",
33+
/**
34+
* A location attachment.
35+
*/
36+
Location = "location",
37+
/**
38+
* A poll attachment.
39+
*/
40+
Poll = "poll",
41+
/**
42+
* A quiz attachment.
43+
*/
44+
Quiz = "quiz",
45+
/**
46+
* A button attachment.
47+
*/
48+
Button = "button",
49+
}
50+
51+
export type BaseAttachment = {
52+
type: AttachmentType;
53+
};
54+
55+
export type ImageAttachment = BaseAttachment & {
56+
type: AttachmentType.Image;
57+
url: string;
58+
};
59+
60+
export type VideoAttachment = BaseAttachment & {
61+
type: AttachmentType.Video;
62+
url: string;
63+
thumbnail?: string;
64+
};
65+
66+
export type AudioAttachment = BaseAttachment & {
67+
type: AttachmentType.Audio;
68+
url: string;
69+
duration?: number;
70+
};
71+
72+
export type FileAttachment = BaseAttachment & {
73+
type: AttachmentType.File;
74+
url: string;
75+
size?: number;
76+
mimeType?: string;
77+
};
78+
79+
export type VoiceAttachment = BaseAttachment & {
80+
type: AttachmentType.Voice;
81+
url: string;
82+
duration: number;
83+
};
84+
85+
export type StickerAttachment = BaseAttachment & {
86+
type: AttachmentType.Sticker;
87+
url: string;
88+
};
89+
90+
// Data-based attachments
91+
export type ContactAttachment = BaseAttachment & {
92+
type: AttachmentType.Contact;
93+
data: {
94+
name: string;
95+
phoneNumber: string;
96+
email?: string;
97+
};
98+
};
99+
100+
export type LocationAttachment = BaseAttachment & {
101+
type: AttachmentType.Location;
102+
data: {
103+
latitude: number;
104+
longitude: number;
105+
address?: string;
106+
};
107+
};
108+
109+
export type PollAttachment = BaseAttachment & {
110+
type: AttachmentType.Poll;
111+
data: {
112+
question: string;
113+
options: {
114+
text: string;
115+
votes: number;
116+
}[];
117+
multipleChoice?: boolean;
118+
endTime?: string;
119+
};
120+
};
121+
122+
export type QuizAttachment = BaseAttachment & {
123+
type: AttachmentType.Quiz;
124+
data: {
125+
question: string;
126+
options: string[];
127+
correctAnswer: number;
128+
explanation?: string;
129+
};
130+
};
131+
132+
export type ButtonAttachment = BaseAttachment & {
133+
type: AttachmentType.Button;
134+
data: {
135+
text: string;
136+
url?: string;
137+
action?: string;
138+
payload?: Record<string, unknown>;
139+
};
140+
};
141+
142+
// Union type of all possible attachments
143+
export type Attachment =
144+
| ImageAttachment
145+
| VideoAttachment
146+
| AudioAttachment
147+
| FileAttachment
148+
| VoiceAttachment
149+
| StickerAttachment
150+
| ContactAttachment
151+
| LocationAttachment
152+
| PollAttachment
153+
| QuizAttachment
154+
| ButtonAttachment;

packages/common/src/container.interface.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type React from "react";
2+
import { Attachment } from "./attachment.interface";
23

34
export enum ContainerType {
45
ROOT = "ROOT",
@@ -46,4 +47,9 @@ export interface Container<
4647
* For example, in `Telegram`, if user type `@bot_name`, the bot will be mentioned.
4748
*/
4849
hasBeenMentioned: boolean;
50+
51+
/**
52+
* Attachments that are sent with the message.
53+
*/
54+
attachments: Attachment[];
4955
}

packages/common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export * from "./router.interface";
1010
export * from "./storage.interface";
1111
export * from "./page.interface";
1212
export * from "./compiler.interface";
13+
export * from "./attachment.interface";

packages/common/src/page.interface.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ReactNode } from "react";
2+
import { Attachment } from "./attachment.interface";
23
import { RouteInfoFile } from "./router.interface";
34
import { StorageClientInterface } from "./storage.interface";
45

@@ -65,6 +66,11 @@ export interface PageProps {
6566
* The chatroom id of the current chatroom.
6667
*/
6768
chatroomId: string;
69+
70+
/**
71+
* Attachments that are sent with the message.
72+
*/
73+
attachments: Attachment[];
6874
}
6975

7076
export interface ErrorPageProps {

packages/core/src/core/core.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,15 +189,15 @@ export class Core<T extends Container<BaseChatroomInfo, BaseMessage>>
189189
return container;
190190
},
191191
clientRedirectTo: async (message, path, options) => {
192-
const container = this.adapter.createContainer(message, {
192+
const container = await this.adapter.createContainer(message, {
193193
renderNewMessage: options.renderNewMessage ?? true,
194194
userId: options.userId,
195195
});
196196
await this.redirect(container, { route: path }, options);
197197
return container;
198198
},
199199
reload: async (message: BaseMessage, options: ReloadOptions) => {
200-
const container = this.adapter.createContainer(message, {
200+
const container = await this.adapter.createContainer(message, {
201201
renderNewMessage: options.shouldRenderNewMessage ?? false,
202202
});
203203
// get the current route
@@ -283,10 +283,17 @@ export class Core<T extends Container<BaseChatroomInfo, BaseMessage>>
283283
}
284284

285285
async handleMessageUpdate(request: Request, message: BaseMessage) {
286-
await this.adapter.authorize(request);
287-
await this.adapter.handleMessageUpdate(message);
288-
this.updateLastCommitUpdateTime();
289-
return this.waitForMessageToBeSent();
286+
try {
287+
await this.adapter.authorize(request);
288+
await this.adapter.handleMessageUpdate(message);
289+
this.updateLastCommitUpdateTime();
290+
return this.waitForMessageToBeSent();
291+
} catch (e) {
292+
if (e instanceof SkipError) {
293+
return;
294+
}
295+
throw e;
296+
}
290297
}
291298

292299
async redirect(container: T, routeOrObject: any, options?: RedirectOptions) {
@@ -504,6 +511,7 @@ export class Core<T extends Container<BaseChatroomInfo, BaseMessage>>
504511
hasBeenMentioned: container.hasBeenMentioned,
505512
messageId: container.chatroomInfo.messageId?.toString() as any,
506513
chatroomId: container.chatroomInfo.id.toString() as any,
514+
attachments: container.attachments,
507515
...this.element.props,
508516
...oldProps,
509517
storage: {

0 commit comments

Comments
 (0)