@warriorteam/redai-zalo-sdk 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,336 @@
1
+ # Article Management Service
2
+
3
+ The `ArticleService` and `VideoUploadService` provide comprehensive article management capabilities for Zalo Official Account (OA).
4
+
5
+ ## Features
6
+
7
+ ### ArticleService
8
+ - ✅ Create normal articles with rich content
9
+ - ✅ Create video articles
10
+ - ✅ Update existing articles
11
+ - ✅ Get article details and lists
12
+ - ✅ Remove articles
13
+ - ✅ Track article creation/update progress
14
+ - ✅ Comprehensive validation
15
+
16
+ ### VideoUploadService
17
+ - ✅ Upload video files for articles
18
+ - ✅ Check video processing status
19
+ - ✅ Wait for upload completion with polling
20
+ - ✅ Upload videos from URLs
21
+ - ✅ Get video information
22
+
23
+ ## Prerequisites
24
+
25
+ 1. **OA Requirements:**
26
+ - OA must have permission to create articles
27
+ - Access token must have "manage_article" scope
28
+ - OA must have active status and be verified
29
+
30
+ 2. **Content Limits:**
31
+ - Title: max 150 characters
32
+ - Author: max 50 characters (normal articles only)
33
+ - Description: max 300 characters
34
+ - Image size: max 1MB per image
35
+ - Video size: max 50MB per video
36
+ - Video formats: MP4, AVI only
37
+
38
+ ## Usage
39
+
40
+ ### Initialize SDK
41
+
42
+ ```typescript
43
+ import { ZaloSDK } from 'redai-zalo-sdk';
44
+
45
+ const sdk = new ZaloSDK({
46
+ appId: 'your_app_id',
47
+ appSecret: 'your_app_secret',
48
+ });
49
+
50
+ const article = sdk.article;
51
+ const videoUpload = sdk.videoUpload;
52
+ ```
53
+
54
+ ### 1. Create Normal Article
55
+
56
+ ```typescript
57
+ import { ArticleType, ArticleStatus, CommentStatus, CoverType, BodyItemType } from 'redai-zalo-sdk';
58
+
59
+ const normalArticle = {
60
+ type: ArticleType.NORMAL,
61
+ title: "Welcome to Our Service",
62
+ author: "RedAI Team",
63
+ description: "This is a comprehensive guide to our new features",
64
+ cover: {
65
+ cover_type: CoverType.PHOTO,
66
+ photo_url: "https://example.com/cover.jpg",
67
+ status: ArticleStatus.SHOW
68
+ },
69
+ body: [
70
+ {
71
+ type: BodyItemType.TEXT,
72
+ content: "Welcome to our new service! Here's what you need to know..."
73
+ },
74
+ {
75
+ type: BodyItemType.IMAGE,
76
+ url: "https://example.com/image1.jpg"
77
+ },
78
+ {
79
+ type: BodyItemType.TEXT,
80
+ content: "For more information, please contact us."
81
+ }
82
+ ],
83
+ tracking_link: "https://your-website.com/tracking",
84
+ status: ArticleStatus.SHOW,
85
+ comment: CommentStatus.SHOW
86
+ };
87
+
88
+ const result = await article.createNormalArticle(accessToken, normalArticle);
89
+ console.log(`Article creation token: ${result.token}`);
90
+ ```
91
+
92
+ ### 2. Create Video Article
93
+
94
+ ```typescript
95
+ const videoArticle = {
96
+ type: ArticleType.VIDEO,
97
+ title: "Product Demo Video",
98
+ description: "Watch our latest product demonstration",
99
+ video_id: "your_video_id", // Get from video upload
100
+ avatar: "https://example.com/thumbnail.jpg",
101
+ status: ArticleStatus.SHOW,
102
+ comment: CommentStatus.SHOW
103
+ };
104
+
105
+ const result = await article.createVideoArticle(accessToken, videoArticle);
106
+ console.log(`Video article creation token: ${result.token}`);
107
+ ```
108
+
109
+ ### 3. Upload Video for Articles
110
+
111
+ ```typescript
112
+ // Upload video file
113
+ const videoFile = new File([videoBuffer], 'demo.mp4', { type: 'video/mp4' });
114
+ const uploadResult = await videoUpload.uploadVideo(accessToken, videoFile);
115
+
116
+ // Wait for processing completion
117
+ const finalResult = await videoUpload.waitForUploadCompletion(
118
+ accessToken,
119
+ uploadResult.token,
120
+ 5 * 60 * 1000, // 5 minutes timeout
121
+ 5 * 1000 // 5 seconds polling interval
122
+ );
123
+
124
+ console.log(`Video ID: ${finalResult.video_id}`);
125
+ ```
126
+
127
+ ### 4. Upload Video from URL
128
+
129
+ ```typescript
130
+ const uploadResult = await videoUpload.uploadVideoFromUrl(
131
+ accessToken,
132
+ 'https://example.com/video.mp4'
133
+ );
134
+
135
+ const finalResult = await videoUpload.waitForUploadCompletion(
136
+ accessToken,
137
+ uploadResult.token
138
+ );
139
+ ```
140
+
141
+ ### 5. Check Article Creation Progress
142
+
143
+ ```typescript
144
+ const progress = await article.checkArticleProcess(accessToken, token);
145
+
146
+ switch (progress.status) {
147
+ case 'processing':
148
+ console.log('Article is still being processed...');
149
+ break;
150
+ case 'success':
151
+ console.log(`Article created with ID: ${progress.article_id}`);
152
+ break;
153
+ case 'failed':
154
+ console.error(`Article creation failed: ${progress.error_message}`);
155
+ break;
156
+ }
157
+ ```
158
+
159
+ ### 6. Get Article Details
160
+
161
+ ```typescript
162
+ const articleDetail = await article.getArticleDetail(accessToken, articleId);
163
+ console.log('Article details:', articleDetail);
164
+ ```
165
+
166
+ ### 7. Get Article List
167
+
168
+ ```typescript
169
+ const articleList = await article.getArticleList(accessToken, {
170
+ offset: 0,
171
+ limit: 20,
172
+ type: 'normal' // or 'video'
173
+ });
174
+
175
+ console.log(`Found ${articleList.data.total} articles`);
176
+ articleList.data.articles.forEach(article => {
177
+ console.log(`- ${article.title} (${article.total_view} views)`);
178
+ });
179
+ ```
180
+
181
+ ### 8. Update Article
182
+
183
+ ```typescript
184
+ const updateData = {
185
+ id: articleId,
186
+ type: ArticleType.NORMAL,
187
+ title: "Updated Article Title",
188
+ author: "Updated Author",
189
+ description: "Updated description",
190
+ cover: {
191
+ cover_type: CoverType.PHOTO,
192
+ photo_url: "https://example.com/new-cover.jpg",
193
+ status: ArticleStatus.SHOW
194
+ },
195
+ body: [
196
+ {
197
+ type: BodyItemType.TEXT,
198
+ content: "Updated content..."
199
+ }
200
+ ],
201
+ status: ArticleStatus.SHOW
202
+ };
203
+
204
+ const updateResult = await article.updateNormalArticle(accessToken, updateData);
205
+ console.log(`Update token: ${updateResult.token}`);
206
+ ```
207
+
208
+ ### 9. Remove Article
209
+
210
+ ```typescript
211
+ const removeResult = await article.removeArticle(accessToken, articleId);
212
+ console.log(removeResult.message);
213
+ ```
214
+
215
+ ### 10. Check Video Status
216
+
217
+ ```typescript
218
+ const videoStatus = await videoUpload.checkVideoStatus(accessToken, token);
219
+
220
+ console.log(`Status: ${videoStatus.status}`);
221
+ console.log(`Progress: ${videoStatus.convert_percent}%`);
222
+
223
+ if (videoStatus.video_id) {
224
+ console.log(`Video ID: ${videoStatus.video_id}`);
225
+ }
226
+ ```
227
+
228
+ ## Error Handling
229
+
230
+ ```typescript
231
+ import { ZaloSDKError } from 'redai-zalo-sdk';
232
+
233
+ try {
234
+ const result = await article.createNormalArticle(accessToken, articleData);
235
+ console.log('Success:', result);
236
+ } catch (error) {
237
+ if (error instanceof ZaloSDKError) {
238
+ console.error('Zalo API Error:', error.message, error.code);
239
+ console.error('Details:', error.details);
240
+ } else {
241
+ console.error('Unexpected error:', error);
242
+ }
243
+ }
244
+ ```
245
+
246
+ ## Complete Example
247
+
248
+ ```typescript
249
+ import { ZaloSDK, ArticleType, CoverType, BodyItemType, ArticleStatus } from 'redai-zalo-sdk';
250
+
251
+ class ArticleManager {
252
+ private sdk: ZaloSDK;
253
+
254
+ constructor() {
255
+ this.sdk = new ZaloSDK({
256
+ appId: process.env.ZALO_APP_ID!,
257
+ appSecret: process.env.ZALO_APP_SECRET!,
258
+ });
259
+ }
260
+
261
+ async createCompleteArticle(accessToken: string) {
262
+ try {
263
+ // 1. Upload video first (if needed)
264
+ const videoFile = new File([videoBuffer], 'demo.mp4');
265
+ const videoUpload = await this.sdk.videoUpload.uploadVideo(accessToken, videoFile);
266
+ const videoResult = await this.sdk.videoUpload.waitForUploadCompletion(
267
+ accessToken,
268
+ videoUpload.token
269
+ );
270
+
271
+ // 2. Create article with video
272
+ const article = await this.sdk.article.createNormalArticle(accessToken, {
273
+ type: ArticleType.NORMAL,
274
+ title: "Complete Guide",
275
+ author: "RedAI Team",
276
+ description: "A complete guide with video content",
277
+ cover: {
278
+ cover_type: CoverType.PHOTO,
279
+ photo_url: "https://example.com/cover.jpg",
280
+ status: ArticleStatus.SHOW
281
+ },
282
+ body: [
283
+ {
284
+ type: BodyItemType.TEXT,
285
+ content: "Introduction to our service..."
286
+ },
287
+ {
288
+ type: BodyItemType.VIDEO,
289
+ video_id: videoResult.video_id
290
+ },
291
+ {
292
+ type: BodyItemType.TEXT,
293
+ content: "Thank you for watching!"
294
+ }
295
+ ],
296
+ status: ArticleStatus.SHOW
297
+ });
298
+
299
+ // 3. Wait for article creation
300
+ const articleProgress = await this.sdk.article.checkArticleProcess(
301
+ accessToken,
302
+ article.token
303
+ );
304
+
305
+ return articleProgress;
306
+ } catch (error) {
307
+ console.error('Article creation error:', error);
308
+ throw error;
309
+ }
310
+ }
311
+ }
312
+ ```
313
+
314
+ ## Validation Rules
315
+
316
+ ### Normal Articles
317
+ - Title: required, max 150 characters
318
+ - Author: required, max 50 characters
319
+ - Description: required, max 300 characters
320
+ - Cover: required, must specify type and corresponding URL/ID
321
+ - Body: required, at least one item
322
+
323
+ ### Video Articles
324
+ - Title: required, max 150 characters
325
+ - Description: required, max 300 characters
326
+ - Video ID: required, must be valid uploaded video
327
+ - Avatar: required, thumbnail URL
328
+
329
+ ### Video Files
330
+ - Formats: MP4, AVI only
331
+ - Size: max 50MB
332
+ - Processing: asynchronous, use polling to check status
333
+
334
+ ## API Reference
335
+
336
+ For detailed API documentation, see the TypeScript definitions in the source code. All methods include comprehensive JSDoc comments with parameter descriptions and return types.
@@ -0,0 +1,232 @@
1
+ # Group Management Service
2
+
3
+ The `GroupManagementService` provides comprehensive group management capabilities for Zalo Official Account (OA) using the Group Message Framework (GMF).
4
+
5
+ ## Features
6
+
7
+ - ✅ Create new groups with asset_id
8
+ - ✅ Update group information and avatar
9
+ - ✅ Invite and remove members
10
+ - ✅ Manage pending member requests
11
+ - ✅ Add and remove admin rights
12
+ - ✅ Delete groups
13
+ - ✅ Get group information and member lists
14
+ - ✅ Manage group quota and assets
15
+ - ✅ Get conversation history
16
+
17
+ ## Prerequisites
18
+
19
+ 1. **OA Requirements:**
20
+ - OA must be granted GMF (Group Message Framework) permissions
21
+ - Access token must have "manage_group" and "group_message" scopes
22
+ - OA must have active status and be verified
23
+
24
+ 2. **Limits:**
25
+ - Maximum groups: 10-100 (depends on service package)
26
+ - Maximum members per group: 200 people
27
+ - Group creation frequency: max 10 groups/day
28
+ - Member invitation frequency: max 500 invitations/day
29
+
30
+ ## Usage
31
+
32
+ ### Initialize SDK
33
+
34
+ ```typescript
35
+ import { ZaloSDK } from 'redai-zalo-sdk';
36
+
37
+ const sdk = new ZaloSDK({
38
+ appId: 'your_app_id',
39
+ appSecret: 'your_app_secret',
40
+ });
41
+
42
+ const groupManagement = sdk.groupManagement;
43
+ ```
44
+
45
+ ### 1. Create Group
46
+
47
+ ```typescript
48
+ const groupData = {
49
+ group_name: "Support Group",
50
+ description: "Customer support group",
51
+ asset_id: "your_asset_id", // Get from getAssetId()
52
+ member_uids: ["user1", "user2", "user3"]
53
+ };
54
+
55
+ const result = await groupManagement.createGroup(accessToken, groupData);
56
+ console.log(`Group created with ID: ${result.group_id}`);
57
+ ```
58
+
59
+ ### 2. Get Group Information
60
+
61
+ ```typescript
62
+ const groupInfo = await groupManagement.getGroupInfo(accessToken, groupId);
63
+ console.log('Group details:', groupInfo);
64
+ ```
65
+
66
+ ### 3. Update Group Information
67
+
68
+ ```typescript
69
+ const updateData = {
70
+ group_name: "New Group Name",
71
+ description: "Updated description"
72
+ };
73
+
74
+ await groupManagement.updateGroupInfo(accessToken, groupId, updateData);
75
+ ```
76
+
77
+ ### 4. Invite Members
78
+
79
+ ```typescript
80
+ const inviteData = {
81
+ member_uids: ["user4", "user5"]
82
+ };
83
+
84
+ const result = await groupManagement.inviteMembers(accessToken, groupId, inviteData);
85
+ console.log(`Invited ${result.invited_count} members`);
86
+ ```
87
+
88
+ ### 5. Manage Pending Members
89
+
90
+ ```typescript
91
+ // Get pending members
92
+ const pending = await groupManagement.getPendingMembers(accessToken, groupId);
93
+
94
+ // Accept pending members
95
+ const memberIds = pending.data?.members.map(m => m.user_id) || [];
96
+ await groupManagement.acceptPendingMembers(accessToken, groupId, memberIds);
97
+
98
+ // Or reject pending members
99
+ await groupManagement.rejectPendingMembers(accessToken, groupId, memberIds);
100
+ ```
101
+
102
+ ### 6. Manage Admins
103
+
104
+ ```typescript
105
+ // Add admin rights
106
+ const adminData = { admin_uids: ["user1"] };
107
+ await groupManagement.addAdmins(accessToken, groupId, adminData);
108
+
109
+ // Remove admin rights
110
+ await groupManagement.removeAdmins(accessToken, groupId, adminData);
111
+ ```
112
+
113
+ ### 7. Get Asset ID for Group Creation
114
+
115
+ ```typescript
116
+ // Get single asset_id
117
+ const assetId = await groupManagement.getAssetId(accessToken);
118
+
119
+ // Get all available asset_ids
120
+ const assets = await groupManagement.getAssetIds(accessToken);
121
+ console.log('Available assets:', assets.data);
122
+ ```
123
+
124
+ ### 8. Get Group Members
125
+
126
+ ```typescript
127
+ const members = await groupManagement.getGroupMembers(accessToken, groupId, 0, 10);
128
+ console.log('Group members:', members.data?.members);
129
+ ```
130
+
131
+ ### 9. Remove Members
132
+
133
+ ```typescript
134
+ const memberIds = ["user1", "user2"];
135
+ await groupManagement.removeMembers(accessToken, groupId, memberIds);
136
+ ```
137
+
138
+ ### 10. Delete Group
139
+
140
+ ```typescript
141
+ await groupManagement.deleteGroup(accessToken, groupId);
142
+ console.log('Group deleted successfully');
143
+ ```
144
+
145
+ ### 11. Get Groups of OA
146
+
147
+ ```typescript
148
+ const groups = await groupManagement.getGroupsOfOA(accessToken, 0, 20);
149
+ console.log(`Found ${groups.total} groups:`, groups.groups);
150
+ ```
151
+
152
+ ### 12. Get Group Quota
153
+
154
+ ```typescript
155
+ import { GMFProductType, QuotaType } from 'redai-zalo-sdk';
156
+
157
+ const quota = await groupManagement.getGroupQuota(
158
+ accessToken,
159
+ GMFProductType.GMF10,
160
+ QuotaType.SUB_QUOTA
161
+ );
162
+ console.log('Group quota:', quota);
163
+ ```
164
+
165
+ ## Error Handling
166
+
167
+ ```typescript
168
+ try {
169
+ const result = await groupManagement.createGroup(accessToken, groupData);
170
+ console.log('Success:', result);
171
+ } catch (error) {
172
+ if (error instanceof ZaloSDKError) {
173
+ console.error('Zalo API Error:', error.message, error.code);
174
+ } else {
175
+ console.error('Unexpected error:', error);
176
+ }
177
+ }
178
+ ```
179
+
180
+ ## Complete Example
181
+
182
+ ```typescript
183
+ import { ZaloSDK, GMFProductType } from 'redai-zalo-sdk';
184
+
185
+ class GroupManager {
186
+ private sdk: ZaloSDK;
187
+
188
+ constructor() {
189
+ this.sdk = new ZaloSDK({
190
+ appId: process.env.ZALO_APP_ID!,
191
+ appSecret: process.env.ZALO_APP_SECRET!,
192
+ });
193
+ }
194
+
195
+ async createAndManageGroup(accessToken: string) {
196
+ try {
197
+ // 1. Get asset_id for group creation
198
+ const assetId = await this.sdk.groupManagement.getAssetId(accessToken);
199
+
200
+ // 2. Create new group
201
+ const newGroup = await this.sdk.groupManagement.createGroup(accessToken, {
202
+ group_name: "Support Team",
203
+ description: "Customer support team",
204
+ asset_id: assetId,
205
+ member_uids: ["user1", "user2"]
206
+ });
207
+
208
+ // 3. Invite more members
209
+ await this.sdk.groupManagement.inviteMembers(accessToken, newGroup.group_id, {
210
+ member_uids: ["user3", "user4"]
211
+ });
212
+
213
+ // 4. Add admin
214
+ await this.sdk.groupManagement.addAdmins(accessToken, newGroup.group_id, {
215
+ admin_uids: ["user1"]
216
+ });
217
+
218
+ // 5. Get group info
219
+ const groupInfo = await this.sdk.groupManagement.getGroupInfo(accessToken, newGroup.group_id);
220
+
221
+ return groupInfo;
222
+ } catch (error) {
223
+ console.error('Group management error:', error);
224
+ throw error;
225
+ }
226
+ }
227
+ }
228
+ ```
229
+
230
+ ## API Reference
231
+
232
+ For detailed API documentation, see the TypeScript definitions in the source code. All methods include comprehensive JSDoc comments with parameter descriptions and return types.