@juzi/wechaty-puppet-service 1.0.129 → 1.0.131
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.
- package/dist/cjs/src/auth/call-cred.d.ts +2 -2
- package/dist/cjs/src/auth/call-cred.d.ts.map +1 -1
- package/dist/cjs/src/auth/call-cred.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.d.ts +27 -2
- package/dist/cjs/src/client/puppet-service.d.ts.map +1 -1
- package/dist/cjs/src/client/puppet-service.js +431 -124
- package/dist/cjs/src/client/puppet-service.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.spec.js +107 -0
- package/dist/cjs/src/client/puppet-service.spec.js.map +1 -1
- package/dist/cjs/src/client/room-cache-coordinator.d.ts +14 -0
- package/dist/cjs/src/client/room-cache-coordinator.d.ts.map +1 -0
- package/dist/cjs/src/client/room-cache-coordinator.js +53 -0
- package/dist/cjs/src/client/room-cache-coordinator.js.map +1 -0
- package/dist/cjs/src/client/room-member-cache.spec.d.ts +2 -0
- package/dist/cjs/src/client/room-member-cache.spec.d.ts.map +1 -0
- package/dist/cjs/src/client/room-member-cache.spec.js +417 -0
- package/dist/cjs/src/client/room-member-cache.spec.js.map +1 -0
- package/dist/cjs/src/client/room-member-load.spec.d.ts +2 -0
- package/dist/cjs/src/client/room-member-load.spec.d.ts.map +1 -0
- package/dist/cjs/src/client/room-member-load.spec.js +324 -0
- package/dist/cjs/src/client/room-member-load.spec.js.map +1 -0
- package/dist/cjs/src/package-json.js +4 -4
- package/dist/cjs/src/server/event-stream-manager.d.ts.map +1 -1
- package/dist/cjs/src/server/event-stream-manager.js +30 -0
- package/dist/cjs/src/server/event-stream-manager.js.map +1 -1
- package/dist/cjs/src/server/event-stream-manager.spec.d.ts +3 -0
- package/dist/cjs/src/server/event-stream-manager.spec.d.ts.map +1 -0
- package/dist/cjs/src/server/event-stream-manager.spec.js +22 -0
- package/dist/cjs/src/server/event-stream-manager.spec.js.map +1 -0
- package/dist/cjs/src/server/puppet-implementation.d.ts.map +1 -1
- package/dist/cjs/src/server/puppet-implementation.js +135 -28
- package/dist/cjs/src/server/puppet-implementation.js.map +1 -1
- package/dist/cjs/src/server/puppet-implementation.spec.js +98 -0
- package/dist/cjs/src/server/puppet-implementation.spec.js.map +1 -1
- package/dist/cjs/src/utils/pb-payload-helper.d.ts +10 -0
- package/dist/cjs/src/utils/pb-payload-helper.d.ts.map +1 -1
- package/dist/cjs/src/utils/pb-payload-helper.js +180 -1
- package/dist/cjs/src/utils/pb-payload-helper.js.map +1 -1
- package/dist/cjs/src/utils/room-member-load.spec.d.ts +2 -0
- package/dist/cjs/src/utils/room-member-load.spec.d.ts.map +1 -0
- package/dist/cjs/src/utils/room-member-load.spec.js +83 -0
- package/dist/cjs/src/utils/room-member-load.spec.js.map +1 -0
- package/dist/esm/src/auth/call-cred.d.ts +2 -2
- package/dist/esm/src/auth/call-cred.d.ts.map +1 -1
- package/dist/esm/src/auth/call-cred.js.map +1 -1
- package/dist/esm/src/client/puppet-service.d.ts +27 -2
- package/dist/esm/src/client/puppet-service.d.ts.map +1 -1
- package/dist/esm/src/client/puppet-service.js +432 -125
- package/dist/esm/src/client/puppet-service.js.map +1 -1
- package/dist/esm/src/client/puppet-service.spec.js +107 -0
- package/dist/esm/src/client/puppet-service.spec.js.map +1 -1
- package/dist/esm/src/client/room-cache-coordinator.d.ts +14 -0
- package/dist/esm/src/client/room-cache-coordinator.d.ts.map +1 -0
- package/dist/esm/src/client/room-cache-coordinator.js +49 -0
- package/dist/esm/src/client/room-cache-coordinator.js.map +1 -0
- package/dist/esm/src/client/room-member-cache.spec.d.ts +2 -0
- package/dist/esm/src/client/room-member-cache.spec.d.ts.map +1 -0
- package/dist/esm/src/client/room-member-cache.spec.js +415 -0
- package/dist/esm/src/client/room-member-cache.spec.js.map +1 -0
- package/dist/esm/src/client/room-member-load.spec.d.ts +2 -0
- package/dist/esm/src/client/room-member-load.spec.d.ts.map +1 -0
- package/dist/esm/src/client/room-member-load.spec.js +296 -0
- package/dist/esm/src/client/room-member-load.spec.js.map +1 -0
- package/dist/esm/src/package-json.js +4 -4
- package/dist/esm/src/server/event-stream-manager.d.ts.map +1 -1
- package/dist/esm/src/server/event-stream-manager.js +30 -0
- package/dist/esm/src/server/event-stream-manager.js.map +1 -1
- package/dist/esm/src/server/event-stream-manager.spec.d.ts +3 -0
- package/dist/esm/src/server/event-stream-manager.spec.d.ts.map +1 -0
- package/dist/esm/src/server/event-stream-manager.spec.js +20 -0
- package/dist/esm/src/server/event-stream-manager.spec.js.map +1 -0
- package/dist/esm/src/server/puppet-implementation.d.ts.map +1 -1
- package/dist/esm/src/server/puppet-implementation.js +136 -29
- package/dist/esm/src/server/puppet-implementation.js.map +1 -1
- package/dist/esm/src/server/puppet-implementation.spec.js +98 -0
- package/dist/esm/src/server/puppet-implementation.spec.js.map +1 -1
- package/dist/esm/src/utils/pb-payload-helper.d.ts +10 -0
- package/dist/esm/src/utils/pb-payload-helper.d.ts.map +1 -1
- package/dist/esm/src/utils/pb-payload-helper.js +169 -0
- package/dist/esm/src/utils/pb-payload-helper.js.map +1 -1
- package/dist/esm/src/utils/room-member-load.spec.d.ts +2 -0
- package/dist/esm/src/utils/room-member-load.spec.d.ts.map +1 -0
- package/dist/esm/src/utils/room-member-load.spec.js +58 -0
- package/dist/esm/src/utils/room-member-load.spec.js.map +1 -0
- package/package.json +4 -4
- package/src/auth/call-cred.ts +1 -1
- package/src/client/puppet-service.spec.ts +147 -0
- package/src/client/puppet-service.ts +378 -138
- package/src/client/room-cache-coordinator.ts +50 -0
- package/src/client/room-member-cache.spec.ts +448 -0
- package/src/client/room-member-load.spec.ts +319 -0
- package/src/package-json.ts +4 -4
- package/src/server/event-stream-manager.spec.ts +30 -0
- package/src/server/event-stream-manager.ts +29 -0
- package/src/server/puppet-implementation.spec.ts +127 -0
- package/src/server/puppet-implementation.ts +144 -29
- package/src/utils/pb-payload-helper.ts +150 -0
- package/src/utils/room-member-load.spec.ts +67 -0
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
/* eslint-disable sort-keys */
|
|
21
21
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
22
22
|
import type { Writable } from 'stream'
|
|
23
|
+
import { inspect } from 'util'
|
|
23
24
|
import {
|
|
24
25
|
chunkDecoder,
|
|
25
26
|
chunkEncoder,
|
|
@@ -43,12 +44,33 @@ import {
|
|
|
43
44
|
import { log } from '../config.js'
|
|
44
45
|
import { grpcError } from './grpc-error.js'
|
|
45
46
|
import { EventStreamManager } from './event-stream-manager.js'
|
|
46
|
-
import { OptionalBooleanUnwrapper, OptionalBooleanWrapper, callRecordPayloadToPb, channelPayloadToPb, channelPbToPayload, chatHistoryPayloadToPb, postPbToPayload, urlLinkPayloadToPb, channelCardPayloadToPb } from '../utils/pb-payload-helper.js'
|
|
47
|
+
import { OptionalBooleanUnwrapper, OptionalBooleanWrapper, callRecordPayloadToPb, channelPayloadToPb, channelPbToPayload, chatHistoryPayloadToPb, postPbToPayload, urlLinkPayloadToPb, channelCardPayloadToPb, roomPayloadToPb, roomMemberLoadStateToPb, roomMemberSnapshotToPb, validateRoomMemberLoadState, validateRoomMemberSnapshot, validateRoomMemberRevision } from '../utils/pb-payload-helper.js'
|
|
47
48
|
import { grpcCallTypeToPuppetMedia, puppetCallMediaTypeToGrpc } from '../utils/call-media-mapping.js'
|
|
48
49
|
import { TextContentType } from '@juzi/wechaty-puppet/types'
|
|
49
50
|
|
|
50
51
|
type MessageBatchSendResponse = Awaited<ReturnType<PUPPET.impls.PuppetInterface['messageBatchSendText']>>
|
|
51
52
|
|
|
53
|
+
function roomMemberRpcError<Response> (
|
|
54
|
+
method: string, error: unknown, callback: grpc.sendUnaryData<Response>,
|
|
55
|
+
): void {
|
|
56
|
+
log.error('PuppetServiceImpl', 'roomMemberRpcError() %s() rejection: %s', method, inspect(error))
|
|
57
|
+
if (typeof error === 'object' && error !== null && 'code' in error) {
|
|
58
|
+
const status = error as Record<string, unknown>
|
|
59
|
+
const code = status['code']
|
|
60
|
+
if (typeof code === 'number' && Number.isInteger(code) && code > 0 && code <= 16) {
|
|
61
|
+
const details = typeof status['details'] === 'string' ? status['details']
|
|
62
|
+
: error instanceof Error ? error.message : 'Room member RPC failed'
|
|
63
|
+
callback({ code, details }, null)
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (error instanceof Error && /unsupported/i.test(error.message)) {
|
|
68
|
+
callback({ code: grpc.status.UNIMPLEMENTED, details: error.message }, null)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
grpcError(method, error, callback)
|
|
72
|
+
}
|
|
73
|
+
|
|
52
74
|
type GrpcBatchResult = {
|
|
53
75
|
setConversationId(value: string): void,
|
|
54
76
|
setError(value: string): void,
|
|
@@ -1996,6 +2018,75 @@ function puppetImplementation (
|
|
|
1996
2018
|
}
|
|
1997
2019
|
},
|
|
1998
2020
|
|
|
2021
|
+
roomMemberSync: async (
|
|
2022
|
+
call: grpc.ServerUnaryCall<grpcPuppet.RoomMemberSyncRequest, grpcPuppet.RoomMemberLoadStateResponse>,
|
|
2023
|
+
callback: grpc.sendUnaryData<grpcPuppet.RoomMemberLoadStateResponse>,
|
|
2024
|
+
): Promise<void> => {
|
|
2025
|
+
try {
|
|
2026
|
+
const roomId = call.request.getId()
|
|
2027
|
+
if (!roomId) {
|
|
2028
|
+
return callback({ code: grpc.status.INVALID_ARGUMENT, details: 'roomId is required' }, null)
|
|
2029
|
+
}
|
|
2030
|
+
const options = call.request.getForce() ? { force: true } : undefined
|
|
2031
|
+
if (typeof puppet.roomMemberSync !== 'function') { throw new Error('roomMemberSync unsupported by adapter') }
|
|
2032
|
+
const state = await puppet.roomMemberSync(roomId, options)
|
|
2033
|
+
validateRoomMemberLoadState(state, roomId)
|
|
2034
|
+
return callback(null, roomMemberLoadStateToPb(state))
|
|
2035
|
+
} catch (error) {
|
|
2036
|
+
return roomMemberRpcError('roomMemberSync', error, callback)
|
|
2037
|
+
}
|
|
2038
|
+
},
|
|
2039
|
+
|
|
2040
|
+
roomMemberLoadState: async (
|
|
2041
|
+
call: grpc.ServerUnaryCall<grpcPuppet.RoomMemberLoadStateRequest, grpcPuppet.RoomMemberLoadStateResponse>,
|
|
2042
|
+
callback: grpc.sendUnaryData<grpcPuppet.RoomMemberLoadStateResponse>,
|
|
2043
|
+
): Promise<void> => {
|
|
2044
|
+
try {
|
|
2045
|
+
const roomId = call.request.getId()
|
|
2046
|
+
if (!roomId) {
|
|
2047
|
+
return callback({ code: grpc.status.INVALID_ARGUMENT, details: 'roomId is required' }, null)
|
|
2048
|
+
}
|
|
2049
|
+
if (typeof puppet.roomMemberLoadState !== 'function') { throw new Error('roomMemberLoadState unsupported by adapter') }
|
|
2050
|
+
const state = await puppet.roomMemberLoadState(roomId)
|
|
2051
|
+
validateRoomMemberLoadState(state, roomId)
|
|
2052
|
+
return callback(null, roomMemberLoadStateToPb(state))
|
|
2053
|
+
} catch (error) {
|
|
2054
|
+
return roomMemberRpcError('roomMemberLoadState', error, callback)
|
|
2055
|
+
}
|
|
2056
|
+
},
|
|
2057
|
+
|
|
2058
|
+
roomMemberSnapshot: async (
|
|
2059
|
+
call: grpc.ServerUnaryCall<grpcPuppet.RoomMemberSnapshotRequest, grpcPuppet.RoomMemberSnapshotResponse>,
|
|
2060
|
+
callback: grpc.sendUnaryData<grpcPuppet.RoomMemberSnapshotResponse>,
|
|
2061
|
+
): Promise<void> => {
|
|
2062
|
+
try {
|
|
2063
|
+
const roomId = call.request.getId()
|
|
2064
|
+
const revision = call.request.getRevision()
|
|
2065
|
+
const pageSize = call.request.getPageSize()
|
|
2066
|
+
try {
|
|
2067
|
+
if (!roomId) { throw new Error('roomId is required') }
|
|
2068
|
+
validateRoomMemberRevision(revision)
|
|
2069
|
+
if (!Number.isInteger(pageSize) || pageSize < 0 || pageSize > 500) {
|
|
2070
|
+
throw new Error('pageSize must be an integer between 0 and 500')
|
|
2071
|
+
}
|
|
2072
|
+
} catch (error) {
|
|
2073
|
+
return callback({ code: grpc.status.INVALID_ARGUMENT, details: (error as Error).message }, null)
|
|
2074
|
+
}
|
|
2075
|
+
if (typeof puppet.roomMemberSnapshot !== 'function') { throw new Error('roomMemberSnapshot unsupported by adapter') }
|
|
2076
|
+
const snapshot = await puppet.roomMemberSnapshot(roomId, revision, {
|
|
2077
|
+
pageToken: call.request.getPageToken(), pageSize,
|
|
2078
|
+
})
|
|
2079
|
+
try {
|
|
2080
|
+
validateRoomMemberSnapshot(snapshot, roomId, revision)
|
|
2081
|
+
} catch (error) {
|
|
2082
|
+
return callback({ code: grpc.status.FAILED_PRECONDITION, details: (error as Error).message }, null)
|
|
2083
|
+
}
|
|
2084
|
+
return callback(null, roomMemberSnapshotToPb(snapshot))
|
|
2085
|
+
} catch (error) {
|
|
2086
|
+
return roomMemberRpcError('roomMemberSnapshot', error, callback)
|
|
2087
|
+
}
|
|
2088
|
+
},
|
|
2089
|
+
|
|
1999
2090
|
roomMemberList: async (call, callback) => {
|
|
2000
2091
|
log.verbose('PuppetServiceImpl', 'roomMemberList()')
|
|
2001
2092
|
|
|
@@ -2085,20 +2176,7 @@ function puppetImplementation (
|
|
|
2085
2176
|
|
|
2086
2177
|
const payload = await puppet.roomPayload(roomId)
|
|
2087
2178
|
|
|
2088
|
-
const response =
|
|
2089
|
-
response.setAdminIdsList(payload.adminIdList)
|
|
2090
|
-
response.setAvatar(payload.avatar || '')
|
|
2091
|
-
response.setHandle(payload.handle || '')
|
|
2092
|
-
response.setId(payload.id)
|
|
2093
|
-
response.setMemberIdsList(payload.memberIdList)
|
|
2094
|
-
response.setOwnerId(payload.ownerId || '')
|
|
2095
|
-
response.setTopic(payload.topic)
|
|
2096
|
-
response.setAdditionalInfo(payload.additionalInfo || '')
|
|
2097
|
-
response.setRoomRemark(payload.remark || '')
|
|
2098
|
-
response.setExternal(!!payload.external)
|
|
2099
|
-
if (payload.createTime) {
|
|
2100
|
-
response.setCreateTime(timestampFromMilliseconds(payload.createTime))
|
|
2101
|
-
}
|
|
2179
|
+
const response = roomPayloadToPb(payload)
|
|
2102
2180
|
|
|
2103
2181
|
return callback(null, response)
|
|
2104
2182
|
|
|
@@ -2119,20 +2197,7 @@ function puppetImplementation (
|
|
|
2119
2197
|
|
|
2120
2198
|
const payloads: grpcPuppet.RoomPayloadResponse[] = []
|
|
2121
2199
|
for (const [ _, payload ] of payloadMap.entries()) {
|
|
2122
|
-
const pb =
|
|
2123
|
-
pb.setAdminIdsList(payload.adminIdList)
|
|
2124
|
-
pb.setAvatar(payload.avatar || '')
|
|
2125
|
-
pb.setHandle(payload.handle || '')
|
|
2126
|
-
pb.setId(payload.id)
|
|
2127
|
-
pb.setMemberIdsList(payload.memberIdList)
|
|
2128
|
-
pb.setOwnerId(payload.ownerId || '')
|
|
2129
|
-
pb.setTopic(payload.topic)
|
|
2130
|
-
pb.setAdditionalInfo(payload.additionalInfo || '')
|
|
2131
|
-
pb.setRoomRemark(payload.remark || '')
|
|
2132
|
-
pb.setExternal(!!payload.external)
|
|
2133
|
-
if (payload.createTime) {
|
|
2134
|
-
pb.setCreateTime(timestampFromMilliseconds(payload.createTime))
|
|
2135
|
-
}
|
|
2200
|
+
const pb = roomPayloadToPb(payload)
|
|
2136
2201
|
payloads.push(pb)
|
|
2137
2202
|
}
|
|
2138
2203
|
|
|
@@ -3017,6 +3082,56 @@ function puppetImplementation (
|
|
|
3017
3082
|
}
|
|
3018
3083
|
},
|
|
3019
3084
|
|
|
3085
|
+
orgBroadcastPayload: async (call, callback) => {
|
|
3086
|
+
log.verbose('PuppetServiceImpl', 'orgBroadcastPayload()')
|
|
3087
|
+
|
|
3088
|
+
try {
|
|
3089
|
+
const orgBroadcastId = call.request.getId()
|
|
3090
|
+
const payload = await puppet.orgBroadcastPayload(orgBroadcastId)
|
|
3091
|
+
|
|
3092
|
+
const response = new grpcPuppet.OrgBroadcastPayloadResponse()
|
|
3093
|
+
response.setId(payload.id)
|
|
3094
|
+
response.setSendType(payload.sendType)
|
|
3095
|
+
response.setConversationType(payload.conversationType)
|
|
3096
|
+
response.setCreatorId(payload.creatorId ?? '')
|
|
3097
|
+
response.setExecTime(payload.execTime)
|
|
3098
|
+
response.setStatus(payload.status)
|
|
3099
|
+
response.setCanCancel(payload.canCancel)
|
|
3100
|
+
response.setAllowSelect(payload.allowSelect)
|
|
3101
|
+
response.setSent(payload.sent)
|
|
3102
|
+
response.setTotalCount(payload.totalCount)
|
|
3103
|
+
response.setSentCount(payload.sentCount)
|
|
3104
|
+
response.setContentListJson(payload.contentListJson)
|
|
3105
|
+
response.setTargetsList(payload.targets.map(target => {
|
|
3106
|
+
const targetPb = new grpcPuppet.OrgBroadcastTarget()
|
|
3107
|
+
targetPb.setContactId(target.contactId ?? '')
|
|
3108
|
+
targetPb.setRoomId(target.roomId ?? '')
|
|
3109
|
+
targetPb.setStatus(target.status as number as grpcPuppet.OrgBroadcastTargetStatusMap[keyof grpcPuppet.OrgBroadcastTargetStatusMap])
|
|
3110
|
+
return targetPb
|
|
3111
|
+
}))
|
|
3112
|
+
|
|
3113
|
+
return callback(null, response)
|
|
3114
|
+
} catch (e) {
|
|
3115
|
+
return grpcError('orgBroadcastPayload', e, callback)
|
|
3116
|
+
}
|
|
3117
|
+
},
|
|
3118
|
+
|
|
3119
|
+
orgBroadcastExecute: async (call, callback) => {
|
|
3120
|
+
log.verbose('PuppetServiceImpl', 'orgBroadcastExecute()')
|
|
3121
|
+
|
|
3122
|
+
try {
|
|
3123
|
+
const orgBroadcastId = call.request.getId()
|
|
3124
|
+
const targetIds = call.request.getTargetIdsList()
|
|
3125
|
+
|
|
3126
|
+
// an empty target_ids on the wire means all targets of the org broadcast
|
|
3127
|
+
await puppet.orgBroadcastExecute(orgBroadcastId, targetIds.length ? targetIds : undefined)
|
|
3128
|
+
|
|
3129
|
+
return callback(null, new grpcPuppet.OrgBroadcastExecuteResponse())
|
|
3130
|
+
} catch (e) {
|
|
3131
|
+
return grpcError('orgBroadcastExecute', e, callback)
|
|
3132
|
+
}
|
|
3133
|
+
},
|
|
3134
|
+
|
|
3020
3135
|
download: async (call) => {
|
|
3021
3136
|
log.verbose('PuppetServiceImpl', 'download()')
|
|
3022
3137
|
|
|
@@ -6,8 +6,91 @@ import {
|
|
|
6
6
|
import * as PUPPET from '@juzi/wechaty-puppet'
|
|
7
7
|
import type { FileBox, FileBoxInterface } from 'file-box'
|
|
8
8
|
|
|
9
|
+
import { millisecondsFromTimestamp, timestampFromMilliseconds } from '../pure-functions/timestamp.js'
|
|
10
|
+
|
|
9
11
|
type grpcPuppet = typeof puppet
|
|
10
12
|
|
|
13
|
+
export function roomPbToPayload (pb: puppet.RoomPayloadResponse): PUPPET.payloads.Room {
|
|
14
|
+
const createTime = pb.getCreateTime()
|
|
15
|
+
const loadedAt = pb.getMemberLoadedAt()
|
|
16
|
+
return {
|
|
17
|
+
adminIdList: pb.getAdminIdsList(),
|
|
18
|
+
avatar: pb.getAvatar(),
|
|
19
|
+
handle: pb.getHandle(),
|
|
20
|
+
id: pb.getId(),
|
|
21
|
+
memberIdList: pb.getMemberIdsList(),
|
|
22
|
+
ownerId: pb.getOwnerId(),
|
|
23
|
+
topic: pb.getTopic(),
|
|
24
|
+
additionalInfo: pb.getAdditionalInfo(),
|
|
25
|
+
remark: pb.getRoomRemark(),
|
|
26
|
+
external: pb.getExternal(),
|
|
27
|
+
...(createTime ? { createTime: millisecondsFromTimestamp(createTime) } : {}),
|
|
28
|
+
memberCount: pb.getMemberCount(),
|
|
29
|
+
memberLoadMode: pb.getMemberLoadMode(),
|
|
30
|
+
memberLoadStatus: pb.getMemberLoadStatus(),
|
|
31
|
+
memberLoadRevision: pb.getMemberLoadRevision(),
|
|
32
|
+
...(loadedAt ? { memberLoadedAt: millisecondsFromTimestamp(loadedAt) } : {}),
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function roomPayloadToPb (payload: PUPPET.payloads.Room): puppet.RoomPayloadResponse {
|
|
37
|
+
const pb = new puppet.RoomPayloadResponse()
|
|
38
|
+
pb.setAdminIdsList(payload.adminIdList)
|
|
39
|
+
pb.setAvatar(payload.avatar || '')
|
|
40
|
+
pb.setHandle(payload.handle || '')
|
|
41
|
+
pb.setId(payload.id)
|
|
42
|
+
pb.setMemberIdsList(payload.memberIdList)
|
|
43
|
+
pb.setOwnerId(payload.ownerId || '')
|
|
44
|
+
pb.setTopic(payload.topic)
|
|
45
|
+
pb.setAdditionalInfo(payload.additionalInfo || '')
|
|
46
|
+
pb.setRoomRemark(payload.remark || '')
|
|
47
|
+
pb.setExternal(!!payload.external)
|
|
48
|
+
if (payload.createTime !== undefined) { pb.setCreateTime(timestampFromMilliseconds(payload.createTime)) }
|
|
49
|
+
if (payload.memberCount !== undefined) { pb.setMemberCount(payload.memberCount) }
|
|
50
|
+
if (payload.memberLoadMode !== undefined) { pb.setMemberLoadMode(payload.memberLoadMode) }
|
|
51
|
+
if (payload.memberLoadStatus !== undefined) { pb.setMemberLoadStatus(payload.memberLoadStatus) }
|
|
52
|
+
if (payload.memberLoadRevision !== undefined) { pb.setMemberLoadRevision(payload.memberLoadRevision) }
|
|
53
|
+
if (payload.memberLoadedAt !== undefined) { pb.setMemberLoadedAt(timestampFromMilliseconds(payload.memberLoadedAt)) }
|
|
54
|
+
return pb
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function validateRoomMemberRevision (revision: string): void {
|
|
58
|
+
if (typeof revision !== 'string' || !/^(0|[1-9][0-9]*)$/.test(revision)) {
|
|
59
|
+
throw new Error('Invalid room member revision')
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function validateRoomMemberLoadState (state: unknown, roomId?: string): asserts state is PUPPET.payloads.RoomMemberLoadState {
|
|
64
|
+
if (typeof state !== 'object' || state === null) { throw new Error('Invalid room member load state') }
|
|
65
|
+
const value = state as Record<string, unknown>
|
|
66
|
+
if (typeof value['roomId'] !== 'string' || !value['roomId'].trim()
|
|
67
|
+
|| (roomId !== undefined && value['roomId'] !== roomId)) { throw new Error('Invalid room member roomId') }
|
|
68
|
+
if (typeof value['taskId'] !== 'string') { throw new Error('Invalid room member taskId') }
|
|
69
|
+
if (typeof value['revision'] !== 'string') { throw new Error('Invalid room member revision') }
|
|
70
|
+
validateRoomMemberRevision(value['revision'])
|
|
71
|
+
const status = value['status']
|
|
72
|
+
if (typeof status !== 'number' || !Number.isInteger(status) || status < 0 || status > 4) {
|
|
73
|
+
throw new Error('Invalid room member load status')
|
|
74
|
+
}
|
|
75
|
+
if (value['loadedAt'] !== undefined && (typeof value['loadedAt'] !== 'number' || !Number.isFinite(value['loadedAt']))) {
|
|
76
|
+
throw new Error('Invalid room member loadedAt')
|
|
77
|
+
}
|
|
78
|
+
if (value['error'] !== undefined && typeof value['error'] !== 'string') { throw new Error('Invalid room member error') }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function validateRoomMemberSnapshot (
|
|
82
|
+
snapshot: PUPPET.payloads.RoomMemberSnapshot, roomId: string, revision: string,
|
|
83
|
+
): void {
|
|
84
|
+
if (!roomId || snapshot.roomId !== roomId) { throw new Error('Room member snapshot roomId mismatch') }
|
|
85
|
+
validateRoomMemberRevision(snapshot.revision)
|
|
86
|
+
validateRoomMemberRevision(revision)
|
|
87
|
+
if (snapshot.revision !== revision) { throw new Error('Room member snapshot revision mismatch') }
|
|
88
|
+
if (!Array.isArray(snapshot.members)) { throw new Error('Invalid room member snapshot members') }
|
|
89
|
+
if (snapshot.loadedAt !== undefined && !Number.isFinite(snapshot.loadedAt)) {
|
|
90
|
+
throw new Error('Invalid room member snapshot loadedAt')
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
11
94
|
export const miniProgramPayloadToPb = (grpcPuppet: grpcPuppet, miniProgramPayload: PUPPET.payloads.MiniProgram) => {
|
|
12
95
|
const pbMiniProgramPayload = new grpcPuppet.MiniProgramPayload()
|
|
13
96
|
if (miniProgramPayload.appid) { pbMiniProgramPayload.setAppid(miniProgramPayload.appid) }
|
|
@@ -440,6 +523,73 @@ export const roomMemberPbToPayload = (pb: puppet.RoomMemberPayloadResponse) => {
|
|
|
440
523
|
return payload
|
|
441
524
|
}
|
|
442
525
|
|
|
526
|
+
export function roomMemberPayloadToPb (payload: PUPPET.payloads.RoomMember): puppet.RoomMemberPayloadResponse {
|
|
527
|
+
const pb = new puppet.RoomMemberPayloadResponse()
|
|
528
|
+
pb.setAvatar(payload.avatar)
|
|
529
|
+
pb.setId(payload.id)
|
|
530
|
+
pb.setInviterId(payload.inviterId || '')
|
|
531
|
+
pb.setName(payload.name)
|
|
532
|
+
pb.setRoomAlias(payload.roomAlias || '')
|
|
533
|
+
pb.setAdditionalInfo(payload.additionalInfo || '')
|
|
534
|
+
pb.setJoinScene(payload.joinScene ?? PUPPET.types.RoomMemberJoinScene.Unknown)
|
|
535
|
+
pb.setJoinTime(payload.joinTime ?? 0)
|
|
536
|
+
return pb
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export function roomMemberLoadStateToPb (state: PUPPET.payloads.RoomMemberLoadState): puppet.RoomMemberLoadStateResponse {
|
|
540
|
+
validateRoomMemberLoadState(state, state.roomId)
|
|
541
|
+
const pb = new puppet.RoomMemberLoadStateResponse()
|
|
542
|
+
pb.setId(state.roomId)
|
|
543
|
+
pb.setTaskId(state.taskId)
|
|
544
|
+
pb.setStatus(state.status)
|
|
545
|
+
pb.setRevision(state.revision)
|
|
546
|
+
if (state.loadedAt !== undefined) { pb.setLoadedAt(timestampFromMilliseconds(state.loadedAt)) }
|
|
547
|
+
if (state.error !== undefined) { pb.setError(state.error) }
|
|
548
|
+
return pb
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export function roomMemberLoadStatePbToPayload (
|
|
552
|
+
pb: puppet.RoomMemberLoadStateResponse, roomId: string,
|
|
553
|
+
): PUPPET.payloads.RoomMemberLoadState {
|
|
554
|
+
const loadedAt = pb.getLoadedAt()
|
|
555
|
+
const state: PUPPET.payloads.RoomMemberLoadState = {
|
|
556
|
+
roomId: pb.getId(),
|
|
557
|
+
taskId: pb.getTaskId(),
|
|
558
|
+
status: pb.getStatus(),
|
|
559
|
+
revision: pb.getRevision(),
|
|
560
|
+
...(loadedAt ? { loadedAt: millisecondsFromTimestamp(loadedAt) } : {}),
|
|
561
|
+
...(pb.getError() ? { error: pb.getError() } : {}),
|
|
562
|
+
}
|
|
563
|
+
validateRoomMemberLoadState(state, roomId)
|
|
564
|
+
return state
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export function roomMemberSnapshotToPb (snapshot: PUPPET.payloads.RoomMemberSnapshot): puppet.RoomMemberSnapshotResponse {
|
|
568
|
+
validateRoomMemberSnapshot(snapshot, snapshot.roomId, snapshot.revision)
|
|
569
|
+
const pb = new puppet.RoomMemberSnapshotResponse()
|
|
570
|
+
pb.setId(snapshot.roomId)
|
|
571
|
+
pb.setRevision(snapshot.revision)
|
|
572
|
+
pb.setMembersList(snapshot.members.map(roomMemberPayloadToPb))
|
|
573
|
+
if (snapshot.loadedAt !== undefined) { pb.setLoadedAt(timestampFromMilliseconds(snapshot.loadedAt)) }
|
|
574
|
+
if (snapshot.nextPageToken !== undefined) { pb.setNextPageToken(snapshot.nextPageToken) }
|
|
575
|
+
return pb
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
export function roomMemberSnapshotPbToPayload (
|
|
579
|
+
pb: puppet.RoomMemberSnapshotResponse, roomId: string, revision: string,
|
|
580
|
+
): PUPPET.payloads.RoomMemberSnapshot {
|
|
581
|
+
const loadedAt = pb.getLoadedAt()
|
|
582
|
+
const snapshot: PUPPET.payloads.RoomMemberSnapshot = {
|
|
583
|
+
roomId: pb.getId(),
|
|
584
|
+
revision: pb.getRevision(),
|
|
585
|
+
members: pb.getMembersList().map(roomMemberPbToPayload),
|
|
586
|
+
...(loadedAt ? { loadedAt: millisecondsFromTimestamp(loadedAt) } : {}),
|
|
587
|
+
...(pb.getNextPageToken() ? { nextPageToken: pb.getNextPageToken() } : {}),
|
|
588
|
+
}
|
|
589
|
+
validateRoomMemberSnapshot(snapshot, roomId, revision)
|
|
590
|
+
return snapshot
|
|
591
|
+
}
|
|
592
|
+
|
|
443
593
|
export const contactPbToPayload = (pb: puppet.ContactPayloadResponse) => {
|
|
444
594
|
const payload: PUPPET.payloads.Contact = {
|
|
445
595
|
address : pb.getAddress(),
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { test } from 'tstest'
|
|
2
|
+
import * as PUPPET from '@juzi/wechaty-puppet'
|
|
3
|
+
import { puppet as grpcPuppet } from '@juzi/wechaty-grpc'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
roomPayloadToPb,
|
|
7
|
+
roomPbToPayload,
|
|
8
|
+
roomMemberLoadStateToPb,
|
|
9
|
+
roomMemberLoadStatePbToPayload,
|
|
10
|
+
validateRoomMemberSnapshot,
|
|
11
|
+
} from './pb-payload-helper.js'
|
|
12
|
+
|
|
13
|
+
test('room payload roundtrip retains lazy fields and timestamp zero', async t => {
|
|
14
|
+
const payload: PUPPET.payloads.Room = {
|
|
15
|
+
id: 'room',
|
|
16
|
+
topic: 'topic',
|
|
17
|
+
adminIdList: [],
|
|
18
|
+
memberIdList: [],
|
|
19
|
+
memberCount: 0,
|
|
20
|
+
memberLoadMode: PUPPET.types.RoomMemberLoadMode.Lazy,
|
|
21
|
+
memberLoadStatus: PUPPET.types.RoomMemberLoadStatus.Loaded,
|
|
22
|
+
memberLoadRevision: '9007199254740993',
|
|
23
|
+
memberLoadedAt: 0,
|
|
24
|
+
}
|
|
25
|
+
const result = roomPbToPayload(roomPayloadToPb(payload))
|
|
26
|
+
t.equal(result.memberCount, 0)
|
|
27
|
+
t.equal(result.memberLoadMode, payload.memberLoadMode)
|
|
28
|
+
t.equal(result.memberLoadStatus, payload.memberLoadStatus)
|
|
29
|
+
t.equal(result.memberLoadRevision, payload.memberLoadRevision)
|
|
30
|
+
t.equal(result.memberLoadedAt, 0)
|
|
31
|
+
const legacy = roomPbToPayload(new grpcPuppet.RoomPayloadResponse())
|
|
32
|
+
t.equal(legacy.memberLoadMode, PUPPET.types.RoomMemberLoadMode.Unspecified)
|
|
33
|
+
t.equal(legacy.memberLoadedAt, undefined)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('load state preserves exact revision and rejects invalid responses', async t => {
|
|
37
|
+
const state: PUPPET.payloads.RoomMemberLoadState = {
|
|
38
|
+
roomId: 'room',
|
|
39
|
+
taskId: 'task',
|
|
40
|
+
status: PUPPET.types.RoomMemberLoadStatus.Pending,
|
|
41
|
+
revision: '9007199254740993',
|
|
42
|
+
loadedAt: 0,
|
|
43
|
+
}
|
|
44
|
+
t.same(roomMemberLoadStatePbToPayload(roomMemberLoadStateToPb(state), 'room'), state)
|
|
45
|
+
t.throws(() => roomMemberLoadStatePbToPayload(roomMemberLoadStateToPb(state), 'other'), /roomId/)
|
|
46
|
+
t.throws(() => roomMemberLoadStateToPb({ ...state, revision: '01' }), /revision/)
|
|
47
|
+
t.throws(() => roomMemberLoadStateToPb({ ...state, status: 99 }), /status/)
|
|
48
|
+
const response = roomMemberLoadStateToPb(state)
|
|
49
|
+
response.setStatus(99 as Parameters<typeof response.setStatus>[0])
|
|
50
|
+
t.throws(() => roomMemberLoadStatePbToPayload(response, 'room'), /status/)
|
|
51
|
+
response.setStatus(state.status)
|
|
52
|
+
response.setRevision('01')
|
|
53
|
+
t.throws(() => roomMemberLoadStatePbToPayload(response, 'room'), /revision/)
|
|
54
|
+
const failed: PUPPET.payloads.RoomMemberLoadState = {
|
|
55
|
+
...state, status: PUPPET.types.RoomMemberLoadStatus.Failed, error: 'load failed',
|
|
56
|
+
}
|
|
57
|
+
t.same(roomMemberLoadStatePbToPayload(roomMemberLoadStateToPb(failed), 'room'), failed)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('snapshot must match both room and requested revision', async t => {
|
|
61
|
+
const snapshot: PUPPET.payloads.RoomMemberSnapshot = {
|
|
62
|
+
roomId: 'room', revision: '2', members: [], nextPageToken: 'next',
|
|
63
|
+
}
|
|
64
|
+
t.doesNotThrow(() => validateRoomMemberSnapshot(snapshot, 'room', '2'))
|
|
65
|
+
t.throws(() => validateRoomMemberSnapshot(snapshot, 'room', '1'), /revision/)
|
|
66
|
+
t.throws(() => validateRoomMemberSnapshot(snapshot, 'other', '2'), /roomId/)
|
|
67
|
+
})
|