UNPKG

@warriorteam/redai-zalo-sdk

Version:

Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account, ZNS, Consultation Service, Group Messaging, and Social APIs

1,248 lines (1,005 loc) β€’ 56.7 kB
# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.11.1] - 2025-01-11 ### πŸ”§ API IMPROVEMENTS #### Method Signature Enhancement - **IMPROVED**: `createOAAuthUrl()` method signature vα»›i better parameter order - Changed from: `(redirectUri, state?, usePkce?, pkce?)` - Changed to: `(redirectUri, state?, pkce?, usePkce?)` - **ENHANCED**: More intuitive API design vα»›i PKCE config trΖ°α»›c usePkce flag - **UPDATED**: All examples vΓ  documentation để phΓΉ hợp vα»›i signature mα»›i - **ADDED**: Comprehensive test coverage cho new signature #### Developer Experience - **IMPROVED**: Better IntelliSense support vα»›i clearer parameter ordering - **ENHANCED**: More logical API flow cho PKCE implementation ## [1.11.0] - 2025-01-11 ### πŸ” SECURITY ENHANCEMENTS #### PKCE Support for Official Account Authentication - **ADDED**: PKCE (Proof Key for Code Exchange) support cho Official Account OAuth flow - **ENHANCED**: `createOAAuthUrl()` method vα»›i PKCE parameters vΓ  auto-generated state - **ADDED**: `generatePKCE()` method để tαΊ‘o code_verifier vΓ  code_challenge - **UPDATED**: `getOAAccessToken()` method hα»— trợ code_verifier cho token exchange - **ADDED**: `OAAuthResult` type vα»›i url vΓ  state information - **ADDED**: `createSecureOAAuthUrl()` method vα»›i full PKCE support #### Security Best Practices - **ENHANCED**: Auto-generated state vα»›i prefix 'zalo_oa_' nαΊΏu khΓ΄ng được cung cαΊ₯p - **ADDED**: Comprehensive PKCE documentation vΓ  security guidelines - **IMPROVED**: Type safety cho PKCE flow vα»›i proper TypeScript interfaces ### πŸ“š DOCUMENTATION #### Authentication Guide Updates - **UPDATED**: AUTHENTICATION.md vα»›i PKCE implementation guide - **ADDED**: Security benefits vΓ  best practices cho PKCE - **ADDED**: Complete examples cho PKCE flow - **ADDED**: oa-auth-with-pkce.ts example file ### πŸ”§ TECHNICAL IMPROVEMENTS #### API Compatibility - **MAINTAINED**: Backward compatibility cho existing createOAAuthUrl() method - **ADDED**: Deprecation notice cho old method signature - **ENHANCED**: getAuthUrls() method vα»›i PKCE support ## [1.10.1] - 2025-01-11 ### πŸš€ NEW FEATURES #### Consultation Service Enhancement - **ADDED**: `sendQuoteMessage()` - Gα»­i tin nhαΊ―n tΖ° vαΊ₯n trΓ­ch dαΊ«n (quote message) - **ADDED**: `createQuoteMessage()` - Helper method để tαΊ‘o quote message object - **ADDED**: `apiGetWithHeaders()` - Method hα»— trợ GET request vα»›i custom headers #### API Compliance - **ENHANCED**: SendMessageResponse type vα»›i Δ‘αΊ§y Δ‘α»§ quota information types - **ADDED**: Support cho tαΊ₯t cαΊ£ quota types: reply, sub_quota, purchase_quota, reward_quota - **IMPROVED**: Quota information structure theo Δ‘ΓΊng Zalo API specification ### πŸ”§ TECHNICAL IMPROVEMENTS #### Message Types - **UPDATED**: SendMessageResponse interface vα»›i comprehensive quota fields - **ADDED**: Support cho expired_date, owner_type, owner_id trong quota - **ENHANCED**: Type safety cho quota_type vα»›i union types #### Validation & Error Handling - **ADDED**: Validation cho text length (max 2000 characters) - **ADDED**: Validation cho quote_message_id - **IMPROVED**: Error messages vα»›i detailed information ### πŸ“‹ API Implementation #### Consultation Quote Message API - 100% Compliant βœ… - **Endpoint**: `POST https://openapi.zalo.me/v3.0/oa/message/cs` - **Headers**: access_token βœ… - **Body**: recipient, message vα»›i text vΓ  quote_message_id βœ… - **Response**: message_id, user_id, quota information βœ… ### 🎯 Usage Examples #### Send Quote Message ```typescript const zalo = new ZaloSDK(); // Gα»­i tin nhαΊ―n trΓ­ch dαΊ«n const response = await zalo.consultation.sendQuoteMessage( accessToken, { user_id: "186729651760683225" }, "ChΓ o bαΊ‘n, Shop cΓ³ Δ‘α»‹a chỉ lΓ  182 LΓͺ Đẑi HΓ nh, P15, Q10, HCM", "48687128d04c9410cd5f" // quote_message_id ); console.log("Message ID:", response.message_id); console.log("Quota Type:", response.quota?.quota_type); ``` #### Create Quote Message Object ```typescript const quoteMessage = zalo.consultation.createQuoteMessage( "CαΊ£m Ζ‘n bαΊ‘n Δ‘Γ£ liΓͺn hệ!", "48687128d04c9410cd5f", "Nα»™i dung tin nhαΊ―n gα»‘c" ); ``` #### Handle Different Quota Types ```typescript if (response.quota) { switch (response.quota.quota_type) { case "reply": console.log(`Free replies: ${response.quota.remain}/${response.quota.total}`); break; case "sub_quota": console.log(`Package quota: ${response.quota.remain}/${response.quota.total}`); console.log(`Expires: ${response.quota.expired_date}`); break; case "purchase_quota": case "reward_quota": console.log(`Owner: ${response.quota.owner_type} (${response.quota.owner_id})`); break; } } else { console.log("Charged message (no free quota)"); } ``` ## [1.10.0] - 2025-01-11 ### πŸš€ NEW FEATURES #### Video Upload Service Enhancements - **ADDED**: `uploadVideoAndWaitForCompletion()` - Combined method for upload and status checking - **ADDED**: `VideoUploadStatus` enum for better status code handling - **ADDED**: `apiGetWithHeaders()` method in ZaloClient for custom header requests #### API Compliance Improvements - **FIXED**: Video status check API to use token in header (not query params) per Zalo docs - **UPDATED**: Status codes documentation to match official Zalo API specification - **IMPROVED**: Video upload validation with proper MIME type checking #### Architecture Cleanup - **REMOVED**: Centralized endpoints from ZaloClient - each service now manages its own URLs - **SIMPLIFIED**: ZaloClient to focus only on HTTP methods, not endpoint management - **STANDARDIZED**: All services to use full URLs for better maintainability ### πŸ”§ TECHNICAL IMPROVEMENTS #### Code Organization - **REFACTORED**: Endpoint management - moved from centralized to service-specific - **UPDATED**: All services to use full URLs instead of relative paths - **CLEANED**: ZaloClient from unused endpoint definitions #### Type Safety - **ENHANCED**: Video upload types with proper status enum - **IMPROVED**: Response handling for video upload APIs - **ADDED**: Better error handling for video upload operations ### πŸ“‹ API Compliance Status #### Video Upload APIs - 100% Compliant βœ… - **Upload Video**: `POST /v2.0/article/upload_video/preparevideo` - βœ… Fully compliant - **Check Status**: `GET /v2.0/article/upload_video/verify` - βœ… Fixed header usage - **Article Verify**: `POST /v2.0/article/verify` - βœ… Fully compliant #### Breaking Changes - **ZaloClient**: Removed `endpoints` property and `getEndpointUrl()` method - **VideoUploadService**: `checkVideoStatus()` now uses headers correctly ### 🎯 Usage Examples #### New Combined Video Upload ```typescript const zalo = new ZaloSDK(); // Upload and wait for completion in one call const result = await zalo.videoUpload.uploadVideoAndWaitForCompletion( accessToken, videoBuffer, "video.mp4", 5 * 60 * 1000, // 5 minutes timeout 5 * 1000 // 5 seconds polling ); console.log("Video ID:", result.video_id); console.log("Status:", result.status); // Use VideoUploadStatus enum ``` #### Status Code Handling ```typescript import { VideoUploadStatus } from '@warriorteam/redai-zalo-sdk'; if (status.status === VideoUploadStatus.SUCCESS) { console.log("Video ready:", status.video_id); } else if (status.status === VideoUploadStatus.PROCESSING) { console.log("Still processing:", status.convert_percent + "%"); } ``` ## [1.9.14] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Get Info API Fix - **FIXED**: `GroupDetailResponse` interface to match Zalo API docs 100% - **CHANGED**: Return type from partial data to full API response - **FIXED**: `group_info` field names: `group_name` β†’ `name`, `group_avatar` β†’ `avatar`, `member_count` β†’ `total_member` - **ADDED**: Missing fields in `group_info`: `status`, `max_member` - **REMOVED**: Non-existent fields: `admin_count`, `created_time` - **FIXED**: `asset_info` structure: added `asset_id`, `auto_renew`, removed `status` - **FIXED**: `group_setting` field name: `join_approval` β†’ `join_appr` - **REMOVED**: Non-existent field: `lock_view_member` #### API Structure Corrections - **FIXED**: All nested objects to match actual Zalo API response exactly - **IMPROVED**: Type safety with accurate field definitions and documentation - **STANDARDIZED**: Field types to match API specification (e.g., `max_member` as string) ### πŸ“‹ Migration Guide **Before (v1.9.13) - BROKEN:** ```typescript // ❌ Wrong return type and field names const groupData = await groupService.getGroupInfo(accessToken, groupId); // Returns partial data only if (groupData) { console.log(groupData.group_info.group_name); // ❌ Wrong field name console.log(groupData.group_info.group_avatar); // ❌ Wrong field name console.log(groupData.group_info.member_count); // ❌ Wrong field name console.log(groupData.group_info.admin_count); // ❌ Field doesn't exist console.log(groupData.asset_info.status); // ❌ Field doesn't exist console.log(groupData.group_setting.join_approval); // ❌ Wrong field name } ``` **After (v1.9.14) - CORRECT:** ```typescript // βœ… Correct return type and field names const response = await groupService.getGroupInfo(accessToken, groupId); // βœ… Access response structure correctly if (response.error === 0 && response.data) { const { group_info, asset_info, group_setting } = response.data; // βœ… group_info with correct field names console.log('Name:', group_info.name); // βœ… Correct field name console.log('Avatar:', group_info.avatar); // βœ… Correct field name console.log('Group ID:', group_info.group_id); console.log('Link:', group_info.group_link); console.log('Description:', group_info.group_description); console.log('Status:', group_info.status); // βœ… New field console.log('Total Members:', group_info.total_member); // βœ… Correct field name console.log('Max Members:', group_info.max_member); // βœ… New field (string) console.log('Auto Delete:', group_info.auto_delete_date); // βœ… asset_info with correct structure console.log('Asset Type:', asset_info.asset_type); // gmf10, gmf50, gmf100 console.log('Asset ID:', asset_info.asset_id); // βœ… New field console.log('Valid Through:', asset_info.valid_through); console.log('Auto Renew:', asset_info.auto_renew); // βœ… New field (string) // βœ… group_setting with correct field names console.log('Lock Send Msg:', group_setting.lock_send_msg); console.log('Join Approval:', group_setting.join_appr); // βœ… Correct field name console.log('Enable Msg History:', group_setting.enable_msg_history); console.log('Enable Link Join:', group_setting.enable_link_join); } ``` ### πŸ”§ Technical Details - **API**: `GET https://openapi.zalo.me/v3.0/oa/group/getgroup` - **Response**: Now returns full Zalo API response structure - **Field Names**: All field names now match Zalo API exactly - **Field Types**: Correct types for all fields (e.g., `max_member` as string, `auto_renew` as string) ## [1.9.13] - 2025-01-11 ### 🎯 STABLE RELEASE #### All Group Management APIs Now 100% Compliant with Zalo Docs - **VERIFIED**: All group management APIs have been audited and fixed to match Zalo API documentation exactly - **STANDARDIZED**: Consistent response structures across all group APIs - **OPTIMIZED**: Proper field names, types, and validation throughout - **UNIFIED**: Common interfaces where APIs share similar structures #### APIs Fixed in This Release Series (v1.9.4 - v1.9.13): 1. βœ… **Group Invite Members** - Fixed field names and response structure 2. βœ… **Group Pending Members List** - Fixed member interface and field names 3. βœ… **Group Accept/Reject Pending** - Fixed response structure 4. βœ… **Group Members List** - Fixed member interface and query parameters 5. βœ… **Group Add/Remove Admins** - Fixed request interface and field mapping 6. βœ… **Group List of OA** - Fixed response structure and group item interface 7. βœ… **Group Quota Check** - Fixed asset interface and response type 8. βœ… **Group Recent Chats** - Fixed endpoint, interface, and response structure 9. βœ… **Group Conversation** - Fixed interface and unified with recent chats #### Quality Assurance - **100% API COMPLIANCE**: All APIs now match official Zalo documentation exactly - **TYPE SAFETY**: Comprehensive TypeScript interfaces with accurate field definitions - **VALIDATION**: Proper input validation for all parameters - **ERROR HANDLING**: Consistent error handling across all group management operations - **DOCUMENTATION**: Complete API documentation with examples ### πŸš€ Ready for Production This release represents a complete overhaul of the Group Management service to ensure 100% compliance with Zalo's official API documentation. All APIs have been thoroughly tested and verified. ## [1.9.12] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Conversation API Fix - **FIXED**: `getGroupConversation()` method to match Zalo API docs 100% - **ADDED**: `GroupConversationResponse` interface using `RecentChatMessage` structure - **CHANGED**: Default count parameter from 20 β†’ 5 (matching Zalo API docs) - **REMOVED**: Non-existent parameters: `fromTime`, `toTime` - **FIXED**: Query parameters to not convert numbers to strings - **CHANGED**: Return type to return full API response instead of custom wrapper - **DEPRECATED**: `GroupConversationMessage` interface (use `RecentChatMessage` instead) #### API Structure Corrections - **DISCOVERED**: Conversation API returns identical structure to listrecentchat API - **UNIFIED**: Both APIs now use same `RecentChatMessage` interface - **FIXED**: Message object structure to match actual Zalo API response - **IMPROVED**: Type safety with accurate field definitions - **ADDED**: Comprehensive validation for all input parameters ### πŸ“‹ Migration Guide **Before (v1.9.11) - BROKEN:** ```typescript // ❌ Wrong parameters, return type, and structure const result = await groupService.getGroupConversation( accessToken, groupId, 0, 20, // ❌ Wrong default count fromTime, // ❌ Parameter doesn't exist toTime // ❌ Parameter doesn't exist ); console.log(result.messages); // ❌ Wrong structure console.log(result.total); // ❌ Field doesn't exist result.messages.forEach(msg => { console.log(msg.sender_id); // ❌ Wrong field name console.log(msg.sender_name); // ❌ Wrong field name console.log(msg.content); // ❌ Wrong field name console.log(msg.message_type); // ❌ Wrong field name console.log(msg.sent_time); // ❌ Wrong field name and type }); ``` **After (v1.9.12) - CORRECT:** ```typescript // βœ… Correct parameters and return type const response = await groupService.getGroupConversation( accessToken, groupId, 0, // offset 5 // count (correct default) ); // βœ… Access response structure correctly (same as listrecentchat) if (response.error === 0 && response.data) { response.data.forEach(message => { console.log('Source:', message.src); // βœ… 0=OA, 1=User console.log('Time:', message.time); // βœ… Timestamp (number) console.log('Type:', message.type); // βœ… text, photo, etc. console.log('Message:', message.message); // βœ… Content console.log('Message ID:', message.message_id); // βœ… Message ID console.log('From ID:', message.from_id); // βœ… Sender ID console.log('From Name:', message.from_display_name); // βœ… Sender name console.log('From Avatar:', message.from_avatar); // βœ… Sender avatar console.log('Group ID:', message.group_id); // βœ… Group ID // βœ… Optional fields based on message type if (message.type === 'photo' || message.type === 'GIF') { console.log('Thumbnail:', message.thumb); console.log('URL:', message.url); if (message.description) { console.log('Description:', message.description); } } if (message.type === 'voice') { console.log('Audio URL:', message.url); } if (message.type === 'location') { console.log('Location:', message.location); } }); } ``` ### πŸ”§ Technical Details - **API**: `GET https://openapi.zalo.me/v3.0/oa/group/conversation` - **Default Count**: Changed from 20 to 5 (matching Zalo API docs) - **Query Params**: Only `group_id`, `offset`, `count` (removed non-existent params) - **Response**: Returns identical structure to listrecentchat API - **Message Fields**: All field names and types now match Zalo API exactly ## [1.9.11] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Recent Chats API Fix - **FIXED**: API endpoint from `/recent` β†’ `/listrecentchat` to match Zalo API docs - **ADDED**: `RecentChatMessage` interface for correct message structure - **ADDED**: `RecentChatsResponse` interface for proper API response - **CHANGED**: Default count parameter from 20 β†’ 5 (matching Zalo API docs) - **FIXED**: Query parameters to not convert numbers to strings - **CHANGED**: Return type to return full API response instead of custom wrapper - **DEPRECATED**: `GroupRecentChat` interface (use `RecentChatMessage` instead) #### API Structure Corrections - **FIXED**: Message object structure to match actual Zalo API response (flat structure) - **ADDED**: All missing fields: `src`, `time`, `type`, `message`, `from_id`, `from_display_name`, `from_avatar` - **ADDED**: Optional fields: `links`, `thumb`, `url`, `description`, `location` - **IMPROVED**: Type safety with accurate field definitions - **FIXED**: Query parameter types (offset and count as numbers, not strings) ### πŸ“‹ Migration Guide **Before (v1.9.10) - BROKEN:** ```typescript // ❌ Wrong endpoint, return type, and structure const result = await groupService.getRecentChats(accessToken, 0, 20); console.log(result.chats); // ❌ Wrong structure console.log(result.total); // ❌ Field doesn't exist in Zalo API result.chats.forEach(chat => { console.log(chat.group_name); // ❌ Field doesn't exist console.log(chat.last_message.content); // ❌ Nested structure wrong console.log(chat.unread_count); // ❌ Field doesn't exist }); ``` **After (v1.9.11) - CORRECT:** ```typescript // βœ… Correct endpoint, return type, and default count const response = await groupService.getRecentChats(accessToken, 0, 5); // βœ… Access response structure correctly if (response.error === 0 && response.data) { response.data.forEach(message => { console.log('Source:', message.src); // βœ… 0=OA, 1=User console.log('Time:', message.time); // βœ… Timestamp console.log('Type:', message.type); // βœ… text, photo, etc. console.log('Message:', message.message); // βœ… Content console.log('Message ID:', message.message_id); // βœ… Message ID console.log('From ID:', message.from_id); // βœ… Sender ID console.log('From Name:', message.from_display_name); // βœ… Sender name console.log('From Avatar:', message.from_avatar); // βœ… Sender avatar console.log('Group ID:', message.group_id); // βœ… Group ID // βœ… Optional fields based on message type if (message.links) console.log('Links:', message.links); if (message.thumb) console.log('Thumbnail:', message.thumb); if (message.url) console.log('URL:', message.url); if (message.description) console.log('Description:', message.description); if (message.location) console.log('Location:', message.location); }); } ``` ### πŸ”§ Technical Details - **API**: `GET https://openapi.zalo.me/v3.0/oa/group/listrecentchat` - **Default Count**: Changed from 20 to 5 (matching Zalo API docs) - **Query Params**: Fixed to use proper number types instead of strings - **Response**: Now returns actual Zalo API response structure - **Message Fields**: All field names and types now match Zalo API exactly ## [1.9.10] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Quota API Fix - **FIXED**: `getGroupQuota()` method to use correct response interface - **CHANGED**: Return type from `GroupQuota` β†’ `GroupQuotaMessageResponse` - **FIXED**: `GroupQuotaAsset` interface to match Zalo API docs 100% - **ADDED**: Missing `auto_renew` field in asset information - **REMOVED**: Non-existent `remain` field from asset interface - **IMPROVED**: Field ordering and documentation to match Zalo API exactly #### API Structure Corrections - **FIXED**: Asset object structure to match actual Zalo API response - **REMOVED**: Incorrect `GroupQuota` interface with wrong data structure - **IMPROVED**: Type safety with accurate field definitions - **ADDED**: Comprehensive field documentation ### πŸ“‹ Migration Guide **Before (v1.9.9) - BROKEN:** ```typescript // ❌ Wrong return type and missing fields const quota = await groupService.getGroupQuota(accessToken, "gmf10", "sub_quota"); // Returns GroupQuota with wrong structure if (quota.data) { console.log(quota.data.max_groups); // ❌ Field doesn't exist console.log(quota.data.asset_info); // ❌ Wrong field name quota.data.asset_info?.forEach(asset => { console.log(asset.remain); // ❌ Field doesn't exist // ❌ Missing auto_renew field }); } ``` **After (v1.9.10) - CORRECT:** ```typescript // βœ… Correct return type matching Zalo API const response = await groupService.getGroupQuota(accessToken, "gmf10", "sub_quota"); // βœ… Access response structure correctly if (response.error === 0 && response.data) { response.data.forEach(asset => { console.log('Product Type:', asset.product_type); // βœ… gmf10, gmf50, gmf100 console.log('Quota Type:', asset.quota_type); // βœ… sub_quota, purchase_quota, reward_quota console.log('Asset ID:', asset.asset_id); // βœ… For group creation console.log('Valid Through:', asset.valid_through); // βœ… Expiry date console.log('Auto Renew:', asset.auto_renew); // βœ… New field console.log('Status:', asset.status); // βœ… available/used console.log('Used ID:', asset.used_id); // βœ… group_id if used }); } ``` ### πŸ”§ Technical Details - **API**: `POST https://openapi.zalo.me/v3.0/oa/quota/group` - **Request**: Maintains correct structure (no changes) - **Response**: Now returns actual Zalo API response structure - **Asset Fields**: All field names and types now match Zalo API exactly ## [1.9.9] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Get Groups of OA API Fix - **FIXED**: `GroupsOfOAResponse` interface to match Zalo API docs 100% - **ADDED**: `OAGroupItem` interface for correct group structure - **CHANGED**: Default count parameter from 20 β†’ 5 (matching Zalo API docs) - **FIXED**: Query parameters to not convert numbers to strings - **ADDED**: Missing `group_count` field in response - **FIXED**: Group item field names to match Zalo API exactly - **CHANGED**: Return type to return full API response instead of partial data #### API Structure Corrections - **FIXED**: Group object structure to match actual Zalo API response - **ADDED**: All missing fields: `group_link`, `status`, `group_count` - **FIXED**: Field names: `group_name` β†’ `name`, `group_avatar` β†’ `avatar`, `member_count` β†’ `total_member` - **IMPROVED**: Type safety with accurate field definitions - **FIXED**: Query parameter types (offset and count as numbers, not strings) ### πŸ“‹ Migration Guide **Before (v1.9.8) - BROKEN:** ```typescript // ❌ Wrong return type and default count const result = await groupService.getGroupsOfOA(accessToken, 0, 20); console.log(result.groups); // ❌ Partial data with wrong structure console.log(result.total); // ❌ Missing many fields // ❌ Groups had wrong field names result.groups.forEach(group => { console.log(group.group_name); // ❌ Field doesn't exist console.log(group.group_avatar); // ❌ Field doesn't exist console.log(group.member_count); // ❌ Field doesn't exist }); ``` **After (v1.9.9) - CORRECT:** ```typescript // βœ… Correct return type and default count const response = await groupService.getGroupsOfOA(accessToken, 0, 5); // βœ… Access full response structure if (response.error === 0 && response.data) { console.log('Total groups:', response.data.total); console.log('Group count returned:', response.data.group_count); console.log('Offset:', response.data.offset); console.log('Count:', response.data.count); // βœ… Groups have correct field names response.data.groups.forEach(group => { console.log('Name:', group.name); // βœ… Correct field name console.log('Avatar:', group.avatar); // βœ… Correct field name console.log('Group ID:', group.group_id); // βœ… Correct field name console.log('Group Link:', group.group_link); // βœ… New field console.log('Description:', group.group_description); console.log('Total Members:', group.total_member); // βœ… Correct field name console.log('Status:', group.status); // βœ… New field }); } ``` ### πŸ”§ Technical Details - **API**: `GET https://openapi.zalo.me/v3.0/oa/group/getgroupsofoa` - **Default Count**: Changed from 20 to 5 (matching Zalo API docs) - **Query Params**: Fixed to use proper number types instead of strings - **Response**: Now returns full Zalo API response structure - **Group Fields**: All field names now match Zalo API exactly ## [1.9.8] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Admin Management API Fix - **FIXED**: `GroupAdminActionRequest` interface field name from `admin_uids` β†’ `member_user_ids` - **FIXED**: Field mapping in `addAdmins()` and `removeAdmins()` methods - **ADDED**: Method overloads for easier usage with direct array parameters - **IMPROVED**: Input validation for admin management operations #### API Structure Corrections - **FIXED**: Request field name to match Zalo API docs 100% - **IMPROVED**: Method signatures with overloads for better developer experience - **ADDED**: Comprehensive validation for member user IDs ### πŸ“‹ Migration Guide **Before (v1.9.7) - BROKEN:** ```typescript // ❌ Wrong field name await groupService.addAdmins(accessToken, groupId, { admin_uids: ["user1", "user2"] // ❌ Wrong field name }); await groupService.removeAdmins(accessToken, groupId, { admin_uids: ["user1", "user2"] // ❌ Wrong field name }); ``` **After (v1.9.8) - CORRECT:** ```typescript // βœ… Method 1: Object parameter (correct field name) await groupService.addAdmins(accessToken, groupId, { member_user_ids: ["user1", "user2"] // βœ… Correct field name }); // βœ… Method 2: Direct array parameter (easier) await groupService.addAdmins(accessToken, groupId, [ "user1", "user2" ]); // βœ… Same for removeAdmins await groupService.removeAdmins(accessToken, groupId, [ "user1", "user2" ]); ``` ### πŸ”§ Technical Details - **APIs**: - `POST https://openapi.zalo.me/v3.0/oa/group/addadmins` - `POST https://openapi.zalo.me/v3.0/oa/group/removeadmins` - **Request**: Now uses correct `member_user_ids` field name - **Response**: Maintains correct structure `{ error: number; message: string }` - **Validation**: Added validation for non-empty member user IDs list ## [1.9.7] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group List Members API Fix - **FIXED**: `GroupMembersResponse` member interface to match Zalo API docs 100% - **ADDED**: `GroupMemberInfo` interface for correct member structure - **CHANGED**: Member field name from `display_name` β†’ `name` - **REMOVED**: Non-existent fields: `role`, `joined_time` - **FIXED**: Query parameters to not convert numbers to strings #### API Structure Corrections - **FIXED**: Member object structure to match actual Zalo API response - **REMOVED**: Fictional fields that don't exist in Zalo API (`role`, `joined_time`) - **IMPROVED**: Type safety with accurate field definitions - **FIXED**: Query parameter types (offset and count as numbers, not strings) ### πŸ“‹ Migration Guide **Before (v1.9.6) - BROKEN:** ```typescript // ❌ Wrong field names and extra fields const members = response.data?.members || []; members.forEach(member => { console.log(member.display_name); // ❌ Field doesn't exist console.log(member.role); // ❌ Field doesn't exist console.log(member.joined_time); // ❌ Field doesn't exist }); ``` **After (v1.9.7) - CORRECT:** ```typescript // βœ… Correct field names matching Zalo API const members = response.data?.members || []; members.forEach(member => { console.log(member.name); // βœ… Correct field name console.log(member.user_id); // βœ… Optional for users console.log(member.oa_id); // βœ… Optional for OA console.log(member.avatar); // βœ… Avatar URL }); ``` ### πŸ”§ Technical Details - **API**: `GET https://openapi.zalo.me/v3.0/oa/group/listmember` - **Query Params**: Fixed to use proper number types instead of strings - **Response**: Now accurately reflects actual Zalo API response structure - **Member Fields**: Only `user_id`, `oa_id`, `name`, `avatar` as per official documentation ## [1.9.6] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Accept Pending Members API Fix - **FIXED**: `GroupAcceptPendingMembersResponse` interface to match Zalo API docs 100% - **REMOVED**: Non-existent `data` field with `accepted_count` and `failed_members` - **SIMPLIFIED**: Response structure to only include `error` and `message` as per official docs #### API Structure Corrections - **FIXED**: Response interface to match actual Zalo API response - **REMOVED**: Fictional data fields that don't exist in Zalo API - **IMPROVED**: Type accuracy with correct response structure ### πŸ“‹ Migration Guide **Before (v1.9.5) - BROKEN:** ```typescript // ❌ Wrong response structure with non-existent fields const result = await groupService.acceptPendingMembers(accessToken, groupId, userIds); console.log(result.data?.accepted_count); // ❌ Field doesn't exist console.log(result.data?.failed_members); // ❌ Field doesn't exist ``` **After (v1.9.6) - CORRECT:** ```typescript // βœ… Correct response structure matching Zalo API const result = await groupService.acceptPendingMembers(accessToken, groupId, userIds); console.log(result.error); // βœ… 0 for success console.log(result.message); // βœ… "Success" // βœ… Check success if (result.error === 0) { console.log('βœ… Accept pending members thΓ nh cΓ΄ng!'); } else { console.log('❌ Accept pending members thαΊ₯t bαΊ‘i:', result.message); } ``` ### πŸ”§ Technical Details - **API**: `POST https://openapi.zalo.me/v3.0/oa/group/acceptpendinginvite` - **Request**: Maintains correct structure (no changes) - **Response**: Now accurately reflects actual Zalo API response - **Validation**: Maintains existing validation and error handling ## [1.9.5] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Pending Members API Fix - **FIXED**: `GroupPendingMember` interface to match Zalo API docs 100% - **CHANGED**: Field name from `display_name` β†’ `name` - **REMOVED**: Non-existent fields: `avatar`, `request_time`, `request_message` - **SIMPLIFIED**: Interface to only include fields actually returned by Zalo API #### API Structure Corrections - **FIXED**: Member object structure to match actual Zalo API response - **REMOVED**: Fictional fields that don't exist in Zalo API - **IMPROVED**: Type safety with accurate field definitions ### πŸ“‹ Migration Guide **Before (v1.9.4) - BROKEN:** ```typescript // ❌ Wrong field names and extra fields const members = response.data?.members || []; members.forEach(member => { console.log(member.display_name); // ❌ Field doesn't exist console.log(member.avatar); // ❌ Field doesn't exist console.log(member.request_time); // ❌ Field doesn't exist }); ``` **After (v1.9.5) - CORRECT:** ```typescript // βœ… Correct field names matching Zalo API const members = response.data?.members || []; members.forEach(member => { console.log(member.name); // βœ… Correct field name console.log(member.user_id); // βœ… Correct field name }); ``` ### πŸ”§ Technical Details - **API**: `GET https://openapi.zalo.me/v3.0/oa/group/listpendinginvite` - **Response**: Now accurately reflects actual Zalo API response structure - **Fields**: Only `name` and `user_id` as per official documentation ## [1.9.4] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Invite Members API Fix - **FIXED**: `GroupMemberInviteRequest` interface field name from `member_uids` β†’ `member_user_ids` - **FIXED**: Method implementation to use correct field mapping - **CHANGED**: Return type from custom object to official Zalo API response structure - **ADDED**: `GroupInviteResult` interface for proper API response typing - **ADDED**: Method overload for easier usage with direct array parameter #### API Structure Corrections - **FIXED**: Request field name to match Zalo API docs 100% - **FIXED**: Response structure to return actual API response instead of custom wrapper - **IMPROVED**: Method signature with overloads for better developer experience ### πŸ“‹ Migration Guide **Before (v1.9.3) - BROKEN:** ```typescript // ❌ Wrong field name and return type await groupService.inviteMembers(accessToken, groupId, { member_uids: ["user1", "user2"] // ❌ Wrong field name }); // Returns: { success: boolean; invited_count: number } ❌ Custom structure ``` **After (v1.9.4) - CORRECT:** ```typescript // βœ… Method 1: Object parameter (correct field name) const result = await groupService.inviteMembers(accessToken, groupId, { member_user_ids: ["user1", "user2"] // βœ… Correct field name }); // βœ… Method 2: Direct array parameter (easier) const result = await groupService.inviteMembers(accessToken, groupId, [ "user1", "user2" ]); // βœ… Returns actual Zalo API response console.log(result.error); // 0 for success console.log(result.message); // "Success" ``` ### πŸ”§ Technical Details - **API**: `POST https://openapi.zalo.me/v3.0/oa/group/invite` - **Request**: Now uses correct `member_user_ids` field name - **Response**: Returns actual Zalo API response structure - **Validation**: Maintains existing validation (max 50 members, non-empty list) ## [1.9.3] - 2025-01-11 ### ✨ NEW FEATURES #### Group Asset Update API - COMPLETELY NEW - **ADDED**: `updateGroupAsset()` method for updating group packages and extending expiration - **ADDED**: `GroupAssetUpdateRequest` interface for asset update requests - **ADDED**: Support for both parameter styles: `(accessToken, groupId, assetId)` and `(accessToken, updateData)` - **ADDED**: Complete validation and error handling #### New API Capabilities - **βœ… Increase member limit**: Upgrade from gmf10 β†’ gmf50 β†’ gmf100 - **βœ… Extend group expiration**: Renew expired groups - **βœ… Package management**: Full control over group asset lifecycle ### πŸ“‹ Usage Examples ```typescript // Method 1: Separate parameters await groupService.updateGroupAsset(accessToken, groupId, newAssetId); // Method 2: Object parameter await groupService.updateGroupAsset(accessToken, { group_id: "513c4f117a479319ca56", asset_id: "new_asset_id_for_gmf50" }); // Access response data const result = await groupService.updateGroupAsset(accessToken, groupId, assetId); console.log('New max members:', result.data.group_info.max_member); console.log('Asset type:', result.data.asset_info.asset_type); console.log('Valid through:', result.data.asset_info.valid_through); ``` ### πŸ”§ Technical Details - **API**: `POST https://openapi.zalo.me/v3.0/oa/group/updateasset` - **Response**: Same structure as `GroupUpdateResult` with complete group info - **Validation**: Full input validation for group_id and asset_id - **Error Handling**: Comprehensive error messages and SDK error wrapping ## [1.9.2] - 2025-01-11 ### 🚨 BREAKING CHANGES #### Group Update API Complete Restructure - **FIXED**: `GroupUpdateRequest` interface to match Zalo API docs 100% - **ADDED**: Missing fields: `group_avatar`, `lock_send_msg`, `join_appr`, `enable_msg_history`, `enable_link_join` - **FIXED**: Field name from `description` β†’ `group_description` - **ADDED**: `GroupUpdateResult` interface for complete API response structure - **CHANGED**: `updateGroupInfo()` return type from simple success flag to full response data #### New Response Structure - **ADDED**: Complete response structure with `group_info`, `asset_info`, `group_setting` - **ADDED**: Helper methods: `extractGroupInfo()`, `extractGroupSettings()`, `extractAssetInfo()` - **DEPRECATED**: `updateGroupAvatar()` method (use `updateGroupInfo()` with `group_avatar` field) ### πŸ“‹ Migration Guide **Before (v1.9.1) - BROKEN:** ```typescript // ❌ Missing many fields, wrong field names await groupService.updateGroupInfo(token, groupId, { group_name: "New Name", description: "New Description" // ❌ Wrong field name }); ``` **After (v1.9.2) - CORRECT:** ```typescript // βœ… Complete API support const result = await groupService.updateGroupInfo(token, groupId, { group_name: "New Name", group_description: "New Description", // βœ… Correct field name group_avatar: "https://...", // βœ… Now supported lock_send_msg: true, // βœ… Now supported join_appr: false, // βœ… Now supported enable_msg_history: true, // βœ… Now supported enable_link_join: false // βœ… Now supported }); // Access full response data console.log('Group Info:', result.data.group_info); console.log('Group Settings:', result.data.group_setting); console.log('Asset Info:', result.data.asset_info); // Or use helper methods const groupInfo = groupService.extractGroupInfo(result); const settings = groupService.extractGroupSettings(result); ``` ## [1.9.1] - 2025-01-11 ### πŸ”§ FIXED #### Group Management API Response Structure - **FIXED**: `GroupCreateResult` interface to match Zalo API response 100% - **CHANGED**: Response structure from flat object to proper wrapper with `data`, `error`, `message` - **ADDED**: `GroupCreateData` interface for the actual group data - **ADDED**: `extractGroupData()` helper method to extract data from response #### Response Structure Corrections - **FIXED**: Field names to match Zalo API exactly: - `group_name` β†’ `name` - `member_count` β†’ `total_member` - Added missing fields: `group_link`, `group_description`, `status` - Removed non-existent field: `created_time` ### πŸ“‹ Migration Guide **Before (v1.9.0) - BROKEN:** ```typescript const result = await groupService.createGroup(token, groupData); // result.group_name ❌ Field doesn't exist // result.member_count ❌ Field doesn't exist ``` **After (v1.9.1) - CORRECT:** ```typescript const result = await groupService.createGroup(token, groupData); // Full response: result.data, result.error, result.message const groupData = result.data; // or use extractGroupData(result) // groupData.name βœ… Correct field name // groupData.total_member βœ… Correct field name // groupData.group_link βœ… Available // groupData.status βœ… Available ``` ## [1.9.0] - 2025-01-11 ### 🚨 BREAKING CHANGES #### ZNS Template API Complete Restructure - **FIXED**: `ZNSUpdateTemplateRequest` interface to match Zalo API docs 100% - **FIXED**: `ZNSCreateTemplateRequest` interface to match Zalo API docs 100% - **CHANGED**: Field names from camelCase to snake_case (e.g., `templateId` β†’ `template_id`) - **ADDED**: Required fields: `template_type`, `tag`, `layout`, `tracking_id` - **REMOVED**: Non-existent fields: `templateContent`, `timeout`, `previewUrl` - **FIXED**: `params` structure to match Zalo API specification #### New ZNS Template Structure - **ADDED**: `ZNSTemplateLayout` interface with proper header/body/footer components - **ADDED**: `ZNSLayoutComponent` interface supporting all Zalo component types - **ADDED**: `ZNSTemplateParam` interface with correct param type structure - **ADDED**: `ZNSTemplateCreateEditResponse` interface for API responses #### New Enums and Constants - **ADDED**: `ZNSTemplateType` enum (1-5 for different template types) - **ADDED**: `ZNSTemplateTag` enum ("1"-"3" for Transaction/Customer Care/Promotion) - **ADDED**: `ZNSButtonType` enum (1-8 for different button types) - **ADDED**: `ZNSParamType` enum ("1"-"15" for different parameter types) - **ADDED**: `ZNS_TEMPLATE_TYPES`, `ZNS_TEMPLATE_TAGS`, `ZNS_BUTTON_TYPES`, `ZNS_PARAM_TYPES` constants - **ADDED**: `ZNSValidation` helper functions for validation ### πŸ“‹ Migration Guide **Before (v1.8.1) - BROKEN:** ```typescript const templateData: ZNSUpdateTemplateRequest = { templateId: "123", templateName: "Test", templateContent: "Hello", // ❌ Field doesn't exist in Zalo API templateTag: "1" // ❌ Wrong field name }; ``` **After (v1.9.0) - CORRECT:** ```typescript const templateData: ZNSUpdateTemplateRequest = { template_id: "123", template_name: "Test Template", template_type: ZNSTemplateType.CUSTOM, tag: ZNSTemplateTag.TRANSACTION, layout: { body: { components: [ { TITLE: { value: "Hello World" } } ] } }, tracking_id: "track_001" }; ``` ### πŸ”§ Technical Details - **API Compliance**: Now 100% matches official Zalo API documentation - **Validation**: Added comprehensive validation functions - **Type Safety**: Improved TypeScript types with proper enums - **Constants**: Added helper constants for easier development ## [1.8.1] - 2025-01-10 ### πŸ”§ FIXED #### Upload Image API Corrections - **Fixed**: `UploadImageResult` interface to match Zalo API docs exactly - **Removed**: Unnecessary fields (`url`, `type`, `size`) from response interface - **Fixed**: File size limit from 5MB β†’ 1MB (as per Zalo docs) - **Fixed**: Supported formats from "JPG, PNG, GIF" β†’ "JPG, PNG" only - **Updated**: Comments and documentation to reflect correct specifications ### πŸ“‹ Migration Guide If you're using `uploadImage()` API, note these changes: ```typescript // Before (v1.8.0) const result = await messageService.uploadImage(token, imageData, 'image.gif'); // ❌ GIF not supported // result.url, result.type, result.size // ❌ These fields no longer exist // After (v1.8.1) const result = await messageService.uploadImage(token, imageData, 'image.png'); // βœ… Only JPG/PNG // result.attachment_id // βœ… Only this field exists ``` ### πŸ”§ Technical Details - **API Endpoint**: `https://openapi.zalo.me/v2.0/oa/upload/image` (unchanged) - **Max File Size**: 1MB (corrected from 5MB) - **Supported Formats**: JPG, PNG (removed GIF support) - **Response Structure**: Now 100% matches official Zalo API documentation ## [1.8.0] - 2025-01-10 ### 🚨 BREAKING CHANGES #### Article List API Structure Fixed - **Fixed**: `ArticleListData` interface to match Zalo API docs exactly - **Changed**: `articles` field renamed to `medias` (as per Zalo API response) - **Removed**: `offset` and `count` fields (not in Zalo API response) - **Fixed**: `ArticleListItem` interface to match Zalo API response structure #### Article List Item Fields Updated - **Changed**: `create_time` β†’ `create_date` (matches Zalo API) - **Changed**: `update_time` β†’ `update_date` (matches Zalo API) - **Added**: `thumb` field (article thumbnail URL) - **Removed**: `description`, `comment`, `total_like`, `total_comment` (not in list API response) - **Removed**: All optional fields (`author`, `cover`, `body`, etc.) - these belong to detail API ### πŸ“‹ Migration Guide If you're using `getArticleList()` API, update your code: ```typescript // Before (v1.7.x) const response = await articleService.getArticleList(token, request); const articles = response.data.articles; // ❌ Wrong field name const article = articles[0]; console.log(article.create_time); // ❌ Wrong field name // After (v1.8.0) const response = await articleService.getArticleList(token, request); const articles = response.data.medias; // βœ… Correct field name const article = articles[0]; console.log(article.create_date); // βœ… Correct field name console.log(article.thumb); // βœ… New field available ``` ### πŸ”§ Technical Details - **API Endpoint**: `https://openapi.zalo.me/v2.0/article/getslice` (unchanged) - **Response Structure**: Now 100% matches official Zalo API documentation - **Type Safety**: Enhanced TypeScript definitions for better development experience ## [1.6.0] - 2025-01-09 ### Added #### πŸ†• POST Method for User List Retrieval - **New Method**: `postUserList()` in UserService for POST-based user list retrieval - **Same Endpoint**: Uses identical URL as `getUserList()` but with POST method - **Request Body**: Sends data via request body instead of URL parameters - **Full Feature Parity**: Supports all same parameters as GET method - **Type Safety**: Same TypeScript interfaces and response types #### πŸ“š Enhanced Documentation & Examples - **Comprehensive Example**: New `examples/user-list-post-example.ts` with detailed usage scenarios - **Method Comparison**: Examples comparing GET vs POST approaches - **Pagination Support**: Complete pagination examples using POST method - **Filter Demonstrations**: Examples with tags, followers, and interaction periods ### Technical Details #### POST Method Features - **Endpoint**: `https://openapi.zalo.me/v3.0/oa/user/getlist` (same as GET) - **Method**: POST with JSON body data - **Parameters Support**: - `offset`: Starting position for pagination - `count`: Number of users to retrieve (max 50) - `tag_name`: Filter by specific tag - `last_interaction_period`: Filter by interaction timeframe - `is_follower`: Filter by follower status - **Response Format**: Identical to GET method (`UserListResponse`) - **Error Handling**: Same comprehensive error handling as GET method #### Use Cases for POST Method - **Large Parameter Sets**: Better handling of complex filter combinations - **Request Body Preference**: When POST body is preferred over URL parameters - **API Consistency**: Matching backend API patterns that expect POST - **Future Extensibility**: Easier to extend with additional body parameters ### Usage Examples #### Basic POST Method Usage ```typescript import { ZaloSDK } from "@warriorteam/redai-zalo-sdk"; const zalo = new ZaloSDK({ appId: "your-app-id", appSecret: "your-app-secret" }); // POST method for user list const result = await zalo.user.postUserList(accessToken, { offset: 0, count: 20, tag_name: "VIP_CUSTOMER", is_follower: true }); ``` #### Comparing GET vs POST Methods ```typescript // GET method (existing) const getResult = await zalo.user.getUserList(accessToken, request); // POST method (new) const postResult = await zalo.user.postUserList(accessToken, request); // Results are identical console.log(getResult.total === postResult.total); // true ``` ### Files Added/Modified #### New Files - `examples/user-list-post-example.ts` - Comprehensive POST method examples #### Modified Files - `src/services/user.service.ts` - Added `postUserList()` method and `postList` endpoint ### Breaking Changes None. This release maintains full backward compatibility. ### Migration Guide No migration required. The new `postUserList()` method is an additional option alongside the existing `getUserList()` method. Both methods provide identical functionality: - Use `getUserList()` for GET-based requests (existing behavior) - Use `postUserList()` for POST-based requests (new option) --- ## [1.5.0] - 2025-01-09 ### Added #### πŸ†• OA Quality Information API - **New Method**: `getOAQuality()` in ZNSService for retrieving OA ZNS sending quality information - **Quality Metrics**: Support for current (48-hour) and 7-day quality assessment periods - **Quality Levels**: HIGH, MEDIUM, LOW, UNDEFINED quality level indicators - **Type Safety**: New `ZNSOAQualityInfo` interface for comprehensive type support #### πŸ”§ Enhanced URL Encoding - **Improved Encoding**: Added `encodeURIComponent` for JSON data in UserService API calls - **Better Compatibility**: Enhanced URL parameter handling for special characters - **API Reliability**: Improved data transmission reliability for complex JSON structures ### Technical Details #### OA Quality Information Features - **Real-time Quality**: Get current OA ZNS sending quality (48-hour window) - **Historical Quality**: Get 7-day quality assessment for trend analysis - **Quality Indicators**: - `HIGH`: Excellent sending quality - `MEDIUM`: Average sending quality - `LOW`: Poor sending quality - `UNDEFINED`: Quality not determined (no ZNS sent in assessment period) #### URL Encoding Improvements - **JSON Parameter Encoding**: Proper encoding of JSON data in URL parameters - **Special Character Support**: Enhanced handling of special characters in API requests - **Cross-platform Compatibility**: Improved compatibility across different environments ### Usage Examples #### OA Quality Information ```typescript import { ZaloSDK } from "@warriorteam/redai-zalo-sdk"; const zalo = new ZaloSDK({ appId: "you