diff --git a/packages/onebot/src/actions/extended.ts b/packages/onebot/src/actions/extended.ts index 22b011c1..aae39bca 100644 --- a/packages/onebot/src/actions/extended.ts +++ b/packages/onebot/src/actions/extended.ts @@ -790,7 +790,10 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { try { - const data = await ctx.getProfileLike(userId, start, count); + // getLike treats falsy userId as "self" (it does `isSelf = !userId` + // internally), so passing 0 or undefined is equivalent — matches the + // old `ctx.getProfileLike(userId, start, count)` wrapper exactly. + const data = await ctx.bridge.apis.profile.getLike(userId, start, count); return okResponse(data); } catch (e) { return failedResponse(RETCODE.ACTION_FAILED, String(e)); diff --git a/packages/onebot/src/actions/group-album.ts b/packages/onebot/src/actions/group-album.ts index cd7f8b5d..b7f8b1e9 100644 --- a/packages/onebot/src/actions/group-album.ts +++ b/packages/onebot/src/actions/group-album.ts @@ -1,6 +1,7 @@ import type { ApiHandler, ApiActionContext } from '../api-handler'; import { asNumber, asString } from '../api-handler'; import { RETCODE, failedResponse, okResponse } from '../types'; +import type { JsonValue } from '../types'; export function register(h: ApiHandler, ctx: ApiActionContext): void { h.registerAction('get_group_album_list', async (params) => { @@ -8,7 +9,7 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { if (!groupId) return failedResponse(RETCODE.BAD_REQUEST, 'group_id is required'); try { - const albumList = await ctx.getGroupAlbumList(groupId); + const albumList = await ctx.bridge.apis.groupAlbum.list(groupId); return okResponse(albumList); } catch (error) { const message = error instanceof Error ? error.message : 'failed to get group album list'; @@ -28,7 +29,7 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { if (!file) return failedResponse(RETCODE.BAD_REQUEST, 'file is required'); try { - await ctx.uploadImageToGroupAlbum(groupId, albumId, albumName, file); + await ctx.bridge.apis.groupAlbum.upload(groupId, albumId, albumName, file); return okResponse(null); } catch (error) { const message = error instanceof Error ? error.message : 'failed to upload image to group album'; @@ -45,8 +46,11 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { if (!albumId) return failedResponse(RETCODE.BAD_REQUEST, 'album_id is required'); try { - const mediaList = await ctx.getGroupAlbumMediaList(groupId, albumId, attachInfo); - return okResponse(mediaList); + const mediaList = await ctx.bridge.apis.groupAlbum.getMediaList(groupId, albumId, attachInfo); + // GroupAlbumMediaResult is a concrete domain type; okResponse + // expects JsonValue. The shape is JSON-compatible — same as the + // old ctx wrapper returning `Promise`. + return okResponse(mediaList as unknown as JsonValue); } catch (error) { const message = error instanceof Error ? error.message : 'failed to get group album media list'; return failedResponse(RETCODE.INTERNAL_ERROR, message); @@ -65,8 +69,12 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { if (!content) return failedResponse(RETCODE.BAD_REQUEST, 'content is required'); try { - const comment = await ctx.commentGroupAlbumMedia(groupId, albumId, lloc, content); - return okResponse(comment); + const comment = await ctx.bridge.apis.groupAlbum.comment(groupId, albumId, lloc, content); + // GroupAlbumCommentResult is a concrete domain type; okResponse + // expects JsonValue. The shape is JSON-compatible (no functions + // / classes / bigints), so cast is safe — same as the old ctx + // wrapper returning `Promise`. + return okResponse(comment as unknown as JsonValue); } catch (error) { const message = error instanceof Error ? error.message : 'failed to comment on album media'; return failedResponse(RETCODE.INTERNAL_ERROR, message); @@ -84,7 +92,7 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { } try { - const res = await ctx.likeGroupAlbumMedia(groupId, albumId, batchId, lloc, true); + const res = await ctx.bridge.apis.groupAlbum.like(groupId, albumId, batchId, lloc, true); return okResponse(res); } catch (error) { const message = error instanceof Error ? error.message : 'failed to set like on album media'; @@ -104,7 +112,7 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { } try { - const res = await ctx.likeGroupAlbumMedia(groupId, albumId, batchId, lloc, false); + const res = await ctx.bridge.apis.groupAlbum.like(groupId, albumId, batchId, lloc, false); return okResponse(res); } catch (error) { const message = error instanceof Error ? error.message : 'failed to cancel like on album media'; @@ -122,7 +130,7 @@ export function register(h: ApiHandler, ctx: ApiActionContext): void { } try { - const res = await ctx.deleteGroupAlbumMedia(groupId, albumId, lloc); + const res = await ctx.bridge.apis.groupAlbum.delete(groupId, albumId, lloc); return okResponse(res); } catch (error) { const message = error instanceof Error ? error.message : 'failed to delete album media'; diff --git a/packages/onebot/src/api-handler.ts b/packages/onebot/src/api-handler.ts index f13cac53..60b0649e 100644 --- a/packages/onebot/src/api-handler.ts +++ b/packages/onebot/src/api-handler.ts @@ -80,9 +80,9 @@ export interface ApiActionContext { // Essence (adapter: bakes the set/unset boolean) setEssenceMsg: (messageId: number) => Promise; deleteEssenceMsg: (messageId: number) => Promise; - // Profile reads with OneBot-specific default args - getProfileLike: (userId?: number, start?: number, limit?: number) => Promise; - getGroupEssence: (groupId: number, pageStart?: number, pageLimit?: number) => Promise; + // Profile reads and group essence reads: direct via + // `ctx.bridge.apis.profile.getLike(...)` and + // `ctx.bridge.apis.web.getEssence(...)`. // Friend deletion: direct via `ctx.bridge.apis.friend.delete(userId, block)`. // Module wrappers / multi-dep compositions getGroupMsgHistory: (groupId: number, messageId?: number, count?: number) => Promise; @@ -94,32 +94,18 @@ export interface ApiActionContext { sendForwardMsg: (messages: JsonValue, groupId?: number) => Promise<{ forwardId: string }>; getForwardMsg: (resId: string) => Promise; forwardSingleMsg: (messageId: number, target: { groupId?: number; userId?: number }) => Promise<{ messageId: number }>; - // Extended NapCat-compatible - setFriendRemark: (userId: number, remark: string) => Promise; - setGroupAvatar: (groupId: number, source: string) => Promise; + // setMsgEmojiLike: stays because it threads messageStore meta lookup. setMsgEmojiLike: (messageId: number, emojiId: string, set: boolean) => Promise; - // markGroupMsgAsRead / markPrivateMsgAsRead: direct via - // `ctx.bridge.apis.message.{markGroupRead,markPrivateRead}`. - setOnlineStatus: (status: number, extStatus?: number, batteryStatus?: number) => Promise; - setProfile: (nickname?: string, personalNote?: string) => Promise; - fetchCustomFace: (count?: number) => Promise; - // getEmojiLikes: direct via `ctx.bridge.apis.interaction.getEmojiLikes(...)`. - // Web - getGroupHonorInfo: (groupId: number, type: WebHonorType | string) => Promise; - getGroupEssenceAll: (groupId: number) => Promise; - getGroupAlbumList: (groupId: number) => Promise; - uploadImageToGroupAlbum: (groupId: number, albumId: string, albumName: string, filePath: string) => Promise; - getGroupAlbumMediaList: (groupId: number, albumId: string, attachInfo?: string) => Promise; - commentGroupAlbumMedia: (groupId: number, albumId: string, lloc: string, content: string) => Promise; - deleteGroupAlbumMedia: (groupId: number, albumId: string, lloc: string) => Promise; - likeGroupAlbumMedia: (groupId: number, albumId: string, batchId: string, lloc: string | undefined, isLike: boolean) => Promise; - sendGroupNotice: (groupId: number, content: string, options?: any) => Promise; - getGroupNotice: (groupId: number) => Promise; - deleteGroupNotice: (groupId: number, fid: string) => Promise; - getCookiesStr: (domain: string) => Promise; - getCsrfToken: () => Promise; - getCredentials: (domain: string) => Promise<{ cookies: string; token: number; csrf_token: number }>; - forceFetchClientKey: () => Promise; + // All other extended / NapCat-compatible / Web / Album actions are + // accessed directly through `ctx.bridge.apis..()`: + // * profile area: setProfile / setOnlineStatus / fetchCustomFace / + // setGroupAvatar / getLike + // * friend area: setRemark / delete / handleRequest + // * web area: getHonorInfo / getEssence(All) / sendNotice / + // getNotice / deleteNotice / getCookiesStr / + // getCsrfToken / getCredentials / forceFetchClientKey + // * groupAlbum area: list / upload / getMediaList / comment / + // delete / like // Media lookup (populated from previously dispatched message segments) getImageInfo: (file: string) => Promise; getRecordInfo: (file: string) => Promise; diff --git a/packages/onebot/src/instance-context.ts b/packages/onebot/src/instance-context.ts index 04ebc0a5..c6238e5c 100644 --- a/packages/onebot/src/instance-context.ts +++ b/packages/onebot/src/instance-context.ts @@ -124,15 +124,6 @@ export function buildApiContext(ref: OneBotInstanceContext): ApiActionContext { // request handling moved to direct `ctx.bridge.apis.friend.handleRequest`. handleGroupRequest: (flag, _subType, approve, reason) => handleGroupAddRequest(bridge, flag, approve, reason), - // Essence — bake the set/unset boolean. - setEssenceMsg: (messageId) => setEssenceMessage(bridge, messageStore, messageId, true), - deleteEssenceMsg: (messageId) => setEssenceMessage(bridge, messageStore, messageId, false), - - // Profile-like / get_group_essence — OneBot-specific defaults that the - // action handlers don't supply. - getProfileLike: (userId = undefined, start = 0, limit = 10) => bridge.apis.profile.getLike(userId, start, limit), - getGroupEssence: (groupId, pageStart = 0, pageLimit = 50) => bridge.apis.web.getEssence(groupId, pageStart, pageLimit), - // Message-store-backed history reads. getGroupMsgHistory: (groupId, messageId, count) => getGroupMsgHistory(messageStore, groupId, messageId, count), getFriendMsgHistory: (userId, messageId, count) => getFriendMsgHistory(messageStore, userId, messageId, count), @@ -145,41 +136,21 @@ export function buildApiContext(ref: OneBotInstanceContext): ApiActionContext { sendForwardMsg: (messages, groupId) => uploadForwardMessage(ref, messages, groupId), getForwardMsg: (resId) => getForwardMessage(ref, resId), forwardSingleMsg: (messageId, target) => forwardSingleMessage(ref, messageId, target), - forceFetchClientKey: () => bridge.apis.web.forceFetchClientKey(), - setFriendRemark: (userId, remark) => bridge.apis.friend.setRemark(userId, remark), - setGroupAvatar: (groupId, source) => bridge.apis.profile.setGroupAvatar(groupId, source), - // Cross-store: looks up the meta then routes through Bridge. + // Essence — bakes the set/unset boolean (the only "compose with + // messageStore meta lookup" entry remaining outside of dedicated + // module helpers). + setEssenceMsg: (messageId) => setEssenceMessage(bridge, messageStore, messageId, true), + deleteEssenceMsg: (messageId) => setEssenceMessage(bridge, messageStore, messageId, false), + + // Emoji-like — same shape: meta lookup → bridge call. Group-only + // (QQ doesn't expose emoji reactions on private chats). setMsgEmojiLike: async (messageId, emojiId, set) => { const meta = messageStore.findMeta(messageId); if (!meta) throw new Error('message not found'); - // QQ itself doesn't expose emoji reactions on private chats, so - // there is no wire path to forward this to; fail loudly instead - // of silently no-op'ing. if (!meta.isGroup) throw new Error('emoji reactions are not supported on private messages'); await bridge.apis.interaction.setReaction(meta.targetId, meta.sequence, emojiId, set); }, - setOnlineStatus: (status: number, extStatus?: number, batteryStatus?: number) => bridge.apis.profile.setOnlineStatus(status, extStatus, batteryStatus), - setProfile: (nickname?: string, personalNote?: string) => bridge.apis.profile.setProfile(nickname, personalNote), - - // Web-backed actions. - getGroupHonorInfo: (groupId: number, type: WebHonorType | string) => bridge.apis.web.getHonorInfo(groupId, type), - getGroupEssenceAll: (groupId) => bridge.apis.web.getEssenceAll(groupId), - getGroupAlbumList: (groupId) => bridge.apis.groupAlbum.list(groupId), - uploadImageToGroupAlbum: (groupId, albumId, albumName, filePath) => bridge.apis.groupAlbum.upload(groupId, albumId, albumName, filePath), - getGroupAlbumMediaList: (groupId, albumId, attachInfo) => bridge.apis.groupAlbum.getMediaList(groupId, albumId, attachInfo), - commentGroupAlbumMedia: (groupId, albumId, lloc, content) => bridge.apis.groupAlbum.comment(groupId, albumId, lloc, content), - deleteGroupAlbumMedia: (groupId, albumId, lloc) => bridge.apis.groupAlbum.delete(groupId, albumId, lloc), - likeGroupAlbumMedia: (groupId, albumId, batchId, lloc, isLike) => bridge.apis.groupAlbum.like(groupId, albumId, batchId, lloc, isLike), - sendGroupNotice: (groupId, content, options) => bridge.apis.web.sendNotice(groupId, content, options), - getGroupNotice: (groupId) => bridge.apis.web.getNotice(groupId), - deleteGroupNotice: (groupId, fid) => bridge.apis.web.deleteNotice(groupId, fid), - getCookiesStr: (domain) => bridge.apis.web.getCookiesStr(domain), - getCsrfToken: () => bridge.apis.web.getCsrfToken(), - getCredentials: (domain) => bridge.apis.web.getCredentials(domain), - - // Extended - fetchCustomFace: (count) => bridge.apis.profile.fetchCustomFace(count), // Media lookup. getImageInfo: (file) => getCachedImageInfo(mediaStore, file),