@fg-lab/amadeus-qq 1.2.1 → 1.2.2

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.
Files changed (43) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +55 -53
  3. package/README.zh-CN.md +51 -51
  4. package/REFERENCE.md +49 -49
  5. package/cordis.patch.yml +6 -6
  6. package/docs/DATA_MIGRATION.md +26 -26
  7. package/docs/INSTALL_V1_2.md +22 -22
  8. package/docs/PUBLISHING.md +28 -26
  9. package/docs/RELEASE_CHECKLIST.md +23 -23
  10. package/docs/RELEASE_NOTES.md +38 -38
  11. package/docs/UPGRADE_POLICY.md +26 -26
  12. package/docs/verification/IMAGE_READ_FIX_2026-11-07.md +22 -0
  13. package/docs/verification/LIFE_QQ_BOUNDARY_2026-11-07.md +20 -0
  14. package/lib/client.js +372 -372
  15. package/package.json +94 -91
  16. package/preset.patch.yml +63 -0
  17. package/scripts/symlink-security.mjs +1 -1
  18. package/src/account-profile.js +223 -223
  19. package/src/admin-http.js +361 -361
  20. package/src/audio.js +428 -428
  21. package/src/capabilities.js +785 -785
  22. package/src/client/factory.template.js +82 -82
  23. package/src/client/logic.js +290 -290
  24. package/src/config.js +2 -0
  25. package/src/console/console.css +28 -28
  26. package/src/console/console.js +3 -0
  27. package/src/console/index.html +67 -67
  28. package/src/core.js +21 -4
  29. package/src/files.js +230 -230
  30. package/src/index.js +135 -8
  31. package/src/lease.js +42 -42
  32. package/src/media.js +66 -3
  33. package/src/napcat-action-names.js +186 -186
  34. package/src/native-asr.js +112 -112
  35. package/src/onebot.js +378 -378
  36. package/src/outbound-media.js +309 -309
  37. package/src/owner-workspace.js +394 -394
  38. package/src/permissions.js +20 -0
  39. package/src/preset-guard.mjs +16 -2
  40. package/src/qzone-provider.js +628 -628
  41. package/src/session-provenance.js +74 -74
  42. package/src/setup.js +255 -255
  43. package/src/web-console.js +9 -9
@@ -1,186 +1,186 @@
1
- // API identifiers inventoried from the installed local NapCat bundle on 2026-10-26.
2
- // Presence in the bundle does not prove that the currently running backend supports an action.
3
- export const NAPCAT_ACTION_NAMES = Object.freeze([
4
- "_del_group_notice",
5
- "_get_group_notice",
6
- "_get_model_show",
7
- "_mark_all_as_read",
8
- "_send_group_notice",
9
- "_set_model_show",
10
- ".get_word_slices",
11
- ".handle_quick_operation",
12
- ".ocr_image",
13
- "add_custom_face",
14
- "ArkShareGroup",
15
- "ArkSharePeer",
16
- "bot_exit",
17
- "can_send_image",
18
- "can_send_record",
19
- "cancel_group_album_media_like",
20
- "cancel_group_todo",
21
- "cancel_online_file",
22
- "check_url_safely",
23
- "clean_cache",
24
- "clean_stream_temp_file",
25
- "click_inline_keyboard_button",
26
- "complete_group_todo",
27
- "create_collection",
28
- "create_flash_task",
29
- "create_group_file_folder",
30
- "del_group_album_media",
31
- "delete_custom_face",
32
- "delete_essence_msg",
33
- "delete_friend",
34
- "delete_group_file",
35
- "delete_group_folder",
36
- "delete_msg",
37
- "delete_qzone_msg",
38
- "do_group_album_comment",
39
- "download_file",
40
- "download_file_image_stream",
41
- "download_file_record_stream",
42
- "download_file_stream",
43
- "download_fileset",
44
- "fetch_custom_face",
45
- "fetch_custom_face_detail",
46
- "fetch_emoji_like",
47
- "fetch_ptt_text",
48
- "forward_friend_single_msg",
49
- "forward_group_single_msg",
50
- "friend_poke",
51
- "get_ai_characters",
52
- "get_ai_record",
53
- "get_clientkey",
54
- "get_collection_list",
55
- "get_cookies",
56
- "get_credentials",
57
- "get_csrf_token",
58
- "get_doubt_friends_add_request",
59
- "get_emoji_likes",
60
- "get_essence_msg_list",
61
- "get_file",
62
- "get_fileset_id",
63
- "get_fileset_info",
64
- "get_flash_file_list",
65
- "get_flash_file_url",
66
- "get_forward_msg",
67
- "get_friend_list",
68
- "get_friend_msg_history",
69
- "get_friends_with_category",
70
- "get_group_album_media_list",
71
- "get_group_at_all_remain",
72
- "get_group_detail_info",
73
- "get_group_file_system_info",
74
- "get_group_file_url",
75
- "get_group_files_by_folder",
76
- "get_group_honor_info",
77
- "get_group_ignore_add_request",
78
- "get_group_ignored_notifies",
79
- "get_group_info",
80
- "get_group_info_ex",
81
- "get_group_list",
82
- "get_group_member_info",
83
- "get_group_member_list",
84
- "get_group_msg_history",
85
- "get_group_root_files",
86
- "get_group_share_link",
87
- "get_group_shut_list",
88
- "get_group_signed_list",
89
- "get_group_system_msg",
90
- "get_guild_list",
91
- "get_guild_service_profile",
92
- "get_image",
93
- "get_login_info",
94
- "get_mini_app_ark",
95
- "get_msg",
96
- "get_online_clients",
97
- "get_online_file_msg",
98
- "get_private_file_url",
99
- "get_profile_like",
100
- "get_qun_album_list",
101
- "get_recent_contact",
102
- "get_record",
103
- "get_rkey",
104
- "get_rkey_server",
105
- "get_robot_uin_range",
106
- "get_share_link",
107
- "get_status",
108
- "get_stranger_info",
109
- "get_unidirectional_friend_list",
110
- "get_version_info",
111
- "group_poke",
112
- "mark_group_msg_as_read",
113
- "mark_msg_as_read",
114
- "mark_private_msg_as_read",
115
- "move_group_file",
116
- "nc_get_packet_status",
117
- "nc_get_rkey",
118
- "nc_get_user_status",
119
- "ocr_image",
120
- "receive_online_file",
121
- "refuse_online_file",
122
- "rename_group_file",
123
- "send_ark_share",
124
- "send_flash_msg",
125
- "send_forward_msg",
126
- "send_group_ai_record",
127
- "send_group_ark_share",
128
- "send_group_forward_msg",
129
- "send_group_msg",
130
- "send_group_sign",
131
- "send_like",
132
- "send_msg",
133
- "send_online_file",
134
- "send_online_folder",
135
- "send_packet",
136
- "send_poke",
137
- "send_private_forward_msg",
138
- "send_private_msg",
139
- "send_qzone_msg",
140
- "set_custom_face_desc",
141
- "set_diy_online_status",
142
- "set_doubt_friends_add_request",
143
- "set_essence_msg",
144
- "set_friend_add_request",
145
- "set_friend_remark",
146
- "set_group_add_option",
147
- "set_group_add_request",
148
- "set_group_admin",
149
- "set_group_album_media_like",
150
- "set_group_ban",
151
- "set_group_card",
152
- "set_group_kick",
153
- "set_group_kick_members",
154
- "set_group_leave",
155
- "set_group_member_invite_policy",
156
- "set_group_member_permissions",
157
- "set_group_name",
158
- "set_group_new_member_history_visibility",
159
- "set_group_portrait",
160
- "set_group_remark",
161
- "set_group_robot_add_option",
162
- "set_group_search",
163
- "set_group_sign",
164
- "set_group_special_title",
165
- "set_group_todo",
166
- "set_group_whole_ban",
167
- "set_input_status",
168
- "set_msg_emoji_like",
169
- "set_online_status",
170
- "set_qq_avatar",
171
- "set_qq_profile",
172
- "set_restart",
173
- "set_self_longnick",
174
- "test_auto_register_01",
175
- "test_auto_register_02",
176
- "test_download_stream",
177
- "trans_group_file",
178
- "translate_en2zh",
179
- "unknown",
180
- "upload_file_stream",
181
- "upload_group_file",
182
- "upload_image_to_qun_album",
183
- "upload_images_to_qun_album",
184
- "upload_private_file",
185
- "upload_video_to_qun_album",
186
- ])
1
+ // API identifiers inventoried from the installed local NapCat bundle on 2026-10-26.
2
+ // Presence in the bundle does not prove that the currently running backend supports an action.
3
+ export const NAPCAT_ACTION_NAMES = Object.freeze([
4
+ "_del_group_notice",
5
+ "_get_group_notice",
6
+ "_get_model_show",
7
+ "_mark_all_as_read",
8
+ "_send_group_notice",
9
+ "_set_model_show",
10
+ ".get_word_slices",
11
+ ".handle_quick_operation",
12
+ ".ocr_image",
13
+ "add_custom_face",
14
+ "ArkShareGroup",
15
+ "ArkSharePeer",
16
+ "bot_exit",
17
+ "can_send_image",
18
+ "can_send_record",
19
+ "cancel_group_album_media_like",
20
+ "cancel_group_todo",
21
+ "cancel_online_file",
22
+ "check_url_safely",
23
+ "clean_cache",
24
+ "clean_stream_temp_file",
25
+ "click_inline_keyboard_button",
26
+ "complete_group_todo",
27
+ "create_collection",
28
+ "create_flash_task",
29
+ "create_group_file_folder",
30
+ "del_group_album_media",
31
+ "delete_custom_face",
32
+ "delete_essence_msg",
33
+ "delete_friend",
34
+ "delete_group_file",
35
+ "delete_group_folder",
36
+ "delete_msg",
37
+ "delete_qzone_msg",
38
+ "do_group_album_comment",
39
+ "download_file",
40
+ "download_file_image_stream",
41
+ "download_file_record_stream",
42
+ "download_file_stream",
43
+ "download_fileset",
44
+ "fetch_custom_face",
45
+ "fetch_custom_face_detail",
46
+ "fetch_emoji_like",
47
+ "fetch_ptt_text",
48
+ "forward_friend_single_msg",
49
+ "forward_group_single_msg",
50
+ "friend_poke",
51
+ "get_ai_characters",
52
+ "get_ai_record",
53
+ "get_clientkey",
54
+ "get_collection_list",
55
+ "get_cookies",
56
+ "get_credentials",
57
+ "get_csrf_token",
58
+ "get_doubt_friends_add_request",
59
+ "get_emoji_likes",
60
+ "get_essence_msg_list",
61
+ "get_file",
62
+ "get_fileset_id",
63
+ "get_fileset_info",
64
+ "get_flash_file_list",
65
+ "get_flash_file_url",
66
+ "get_forward_msg",
67
+ "get_friend_list",
68
+ "get_friend_msg_history",
69
+ "get_friends_with_category",
70
+ "get_group_album_media_list",
71
+ "get_group_at_all_remain",
72
+ "get_group_detail_info",
73
+ "get_group_file_system_info",
74
+ "get_group_file_url",
75
+ "get_group_files_by_folder",
76
+ "get_group_honor_info",
77
+ "get_group_ignore_add_request",
78
+ "get_group_ignored_notifies",
79
+ "get_group_info",
80
+ "get_group_info_ex",
81
+ "get_group_list",
82
+ "get_group_member_info",
83
+ "get_group_member_list",
84
+ "get_group_msg_history",
85
+ "get_group_root_files",
86
+ "get_group_share_link",
87
+ "get_group_shut_list",
88
+ "get_group_signed_list",
89
+ "get_group_system_msg",
90
+ "get_guild_list",
91
+ "get_guild_service_profile",
92
+ "get_image",
93
+ "get_login_info",
94
+ "get_mini_app_ark",
95
+ "get_msg",
96
+ "get_online_clients",
97
+ "get_online_file_msg",
98
+ "get_private_file_url",
99
+ "get_profile_like",
100
+ "get_qun_album_list",
101
+ "get_recent_contact",
102
+ "get_record",
103
+ "get_rkey",
104
+ "get_rkey_server",
105
+ "get_robot_uin_range",
106
+ "get_share_link",
107
+ "get_status",
108
+ "get_stranger_info",
109
+ "get_unidirectional_friend_list",
110
+ "get_version_info",
111
+ "group_poke",
112
+ "mark_group_msg_as_read",
113
+ "mark_msg_as_read",
114
+ "mark_private_msg_as_read",
115
+ "move_group_file",
116
+ "nc_get_packet_status",
117
+ "nc_get_rkey",
118
+ "nc_get_user_status",
119
+ "ocr_image",
120
+ "receive_online_file",
121
+ "refuse_online_file",
122
+ "rename_group_file",
123
+ "send_ark_share",
124
+ "send_flash_msg",
125
+ "send_forward_msg",
126
+ "send_group_ai_record",
127
+ "send_group_ark_share",
128
+ "send_group_forward_msg",
129
+ "send_group_msg",
130
+ "send_group_sign",
131
+ "send_like",
132
+ "send_msg",
133
+ "send_online_file",
134
+ "send_online_folder",
135
+ "send_packet",
136
+ "send_poke",
137
+ "send_private_forward_msg",
138
+ "send_private_msg",
139
+ "send_qzone_msg",
140
+ "set_custom_face_desc",
141
+ "set_diy_online_status",
142
+ "set_doubt_friends_add_request",
143
+ "set_essence_msg",
144
+ "set_friend_add_request",
145
+ "set_friend_remark",
146
+ "set_group_add_option",
147
+ "set_group_add_request",
148
+ "set_group_admin",
149
+ "set_group_album_media_like",
150
+ "set_group_ban",
151
+ "set_group_card",
152
+ "set_group_kick",
153
+ "set_group_kick_members",
154
+ "set_group_leave",
155
+ "set_group_member_invite_policy",
156
+ "set_group_member_permissions",
157
+ "set_group_name",
158
+ "set_group_new_member_history_visibility",
159
+ "set_group_portrait",
160
+ "set_group_remark",
161
+ "set_group_robot_add_option",
162
+ "set_group_search",
163
+ "set_group_sign",
164
+ "set_group_special_title",
165
+ "set_group_todo",
166
+ "set_group_whole_ban",
167
+ "set_input_status",
168
+ "set_msg_emoji_like",
169
+ "set_online_status",
170
+ "set_qq_avatar",
171
+ "set_qq_profile",
172
+ "set_restart",
173
+ "set_self_longnick",
174
+ "test_auto_register_01",
175
+ "test_auto_register_02",
176
+ "test_download_stream",
177
+ "trans_group_file",
178
+ "translate_en2zh",
179
+ "unknown",
180
+ "upload_file_stream",
181
+ "upload_group_file",
182
+ "upload_image_to_qun_album",
183
+ "upload_images_to_qun_album",
184
+ "upload_private_file",
185
+ "upload_video_to_qun_album",
186
+ ])
package/src/native-asr.js CHANGED
@@ -1,112 +1,112 @@
1
- import { normalizeMessageId } from './storage.js'
2
- import { sanitizeInboundSegments } from './onebot.js'
3
-
4
- const MAX_TRANSCRIPT_CHARS = 4000
5
- const MAX_RESPONSE_BYTES = 64 * 1024
6
- const PLATFORM_TIMEOUT_MS = 10_000
7
-
8
- function asrError(code) {
9
- const error = new Error(code)
10
- error.code = code
11
- return error
12
- }
13
-
14
- function readPermissionError(changed = false) {
15
- return asrError(changed ? 'QQ_PERMISSION_CHANGED: qq.read' : 'QQ_PERMISSION_DENIED: qq.read')
16
- }
17
-
18
- function assertRead(core, sessionId, changed = false) {
19
- let allowed = false
20
- try {
21
- allowed = core.authorizeSessionCapability(sessionId, 'qq.read') === true
22
- } catch {
23
- allowed = false
24
- }
25
- if (!allowed) throw readPermissionError(changed)
26
- }
27
-
28
- function authorizeScene(core, sessionId) {
29
- try {
30
- return core.authorizedScene(sessionId)
31
- } catch (error) {
32
- const changed = String(error?.message ?? '').startsWith('QQ_PERMISSION_CHANGED')
33
- throw readPermissionError(changed)
34
- }
35
- }
36
-
37
- function boundedText(value) {
38
- if (typeof value !== 'string') throw asrError('QQ_NATIVE_ASR_INVALID_RESPONSE')
39
- const text = value
40
- .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, '')
41
- .trim()
42
- if (text.length === 0) throw asrError('QQ_NATIVE_ASR_EMPTY')
43
- if (text.length > MAX_TRANSCRIPT_CHARS) throw asrError('QQ_NATIVE_ASR_TOO_LONG')
44
- return text
45
- }
46
-
47
- /**
48
- * Use NapCat/QQ's native PTT transcript for one stored record message. The
49
- * model supplies only messageId; Scene, sender and transcript storage target
50
- * all come from the current authorized Session.
51
- */
52
- export async function transcribeMessageRecordNative({
53
- core,
54
- store,
55
- transport,
56
- sessionId,
57
- messageId,
58
- }) {
59
- if (!transport || typeof transport.action !== 'function') throw asrError('QQ_NATIVE_ASR_UNAVAILABLE')
60
- if (transport.status !== undefined && transport.status !== 'connected') throw asrError('QQ_NATIVE_ASR_UNAVAILABLE')
61
-
62
- let id
63
- try {
64
- id = normalizeMessageId(messageId, 'messageId')
65
- } catch {
66
- throw asrError('QQ_NATIVE_ASR_MESSAGE_INVALID')
67
- }
68
-
69
- const scene = authorizeScene(core, sessionId)
70
- assertRead(core, sessionId)
71
-
72
- const row = store.getScene(scene)
73
- const message = row?.messages?.find(item => item.messageId === id)
74
- if (!message) throw asrError('QQ_MESSAGE_SCOPE')
75
-
76
- let segments
77
- try {
78
- segments = sanitizeInboundSegments(message.segments)
79
- } catch {
80
- throw asrError('QQ_NATIVE_ASR_MESSAGE_INVALID')
81
- }
82
- if (!segments.some(segment => segment.type === 'record')) throw asrError('QQ_NATIVE_ASR_NOT_RECORD')
83
-
84
- let response
85
- try {
86
- response = await transport.action('fetch_ptt_text', { message_id: id }, PLATFORM_TIMEOUT_MS, MAX_RESPONSE_BYTES)
87
- } catch (error) {
88
- throw asrError(error?.code === 'ONEBOT_RESPONSE_TOO_LARGE'
89
- ? 'QQ_NATIVE_ASR_RESPONSE_TOO_LARGE'
90
- : 'QQ_NATIVE_ASR_UNAVAILABLE')
91
- }
92
-
93
- assertRead(core, sessionId, true)
94
- if (!response || typeof response !== 'object' || Array.isArray(response)) {
95
- throw asrError('QQ_NATIVE_ASR_INVALID_RESPONSE')
96
- }
97
- const text = boundedText(response.text)
98
- assertRead(core, sessionId, true)
99
-
100
- try {
101
- store.setMessageTranscript(scene, id, text)
102
- } catch {
103
- throw asrError('QQ_NATIVE_ASR_STORAGE_FAILED')
104
- }
105
-
106
- return {
107
- text,
108
- messageId: id,
109
- senderId: message.senderId,
110
- scene: { botId: scene.botId, kind: scene.kind, peerId: scene.peerId },
111
- }
112
- }
1
+ import { normalizeMessageId } from './storage.js'
2
+ import { sanitizeInboundSegments } from './onebot.js'
3
+
4
+ const MAX_TRANSCRIPT_CHARS = 4000
5
+ const MAX_RESPONSE_BYTES = 64 * 1024
6
+ const PLATFORM_TIMEOUT_MS = 10_000
7
+
8
+ function asrError(code) {
9
+ const error = new Error(code)
10
+ error.code = code
11
+ return error
12
+ }
13
+
14
+ function readPermissionError(changed = false) {
15
+ return asrError(changed ? 'QQ_PERMISSION_CHANGED: qq.read' : 'QQ_PERMISSION_DENIED: qq.read')
16
+ }
17
+
18
+ function assertRead(core, sessionId, changed = false) {
19
+ let allowed = false
20
+ try {
21
+ allowed = core.authorizeSessionCapability(sessionId, 'qq.read') === true
22
+ } catch {
23
+ allowed = false
24
+ }
25
+ if (!allowed) throw readPermissionError(changed)
26
+ }
27
+
28
+ function authorizeScene(core, sessionId) {
29
+ try {
30
+ return core.authorizedScene(sessionId)
31
+ } catch (error) {
32
+ const changed = String(error?.message ?? '').startsWith('QQ_PERMISSION_CHANGED')
33
+ throw readPermissionError(changed)
34
+ }
35
+ }
36
+
37
+ function boundedText(value) {
38
+ if (typeof value !== 'string') throw asrError('QQ_NATIVE_ASR_INVALID_RESPONSE')
39
+ const text = value
40
+ .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, '')
41
+ .trim()
42
+ if (text.length === 0) throw asrError('QQ_NATIVE_ASR_EMPTY')
43
+ if (text.length > MAX_TRANSCRIPT_CHARS) throw asrError('QQ_NATIVE_ASR_TOO_LONG')
44
+ return text
45
+ }
46
+
47
+ /**
48
+ * Use NapCat/QQ's native PTT transcript for one stored record message. The
49
+ * model supplies only messageId; Scene, sender and transcript storage target
50
+ * all come from the current authorized Session.
51
+ */
52
+ export async function transcribeMessageRecordNative({
53
+ core,
54
+ store,
55
+ transport,
56
+ sessionId,
57
+ messageId,
58
+ }) {
59
+ if (!transport || typeof transport.action !== 'function') throw asrError('QQ_NATIVE_ASR_UNAVAILABLE')
60
+ if (transport.status !== undefined && transport.status !== 'connected') throw asrError('QQ_NATIVE_ASR_UNAVAILABLE')
61
+
62
+ let id
63
+ try {
64
+ id = normalizeMessageId(messageId, 'messageId')
65
+ } catch {
66
+ throw asrError('QQ_NATIVE_ASR_MESSAGE_INVALID')
67
+ }
68
+
69
+ const scene = authorizeScene(core, sessionId)
70
+ assertRead(core, sessionId)
71
+
72
+ const row = store.getScene(scene)
73
+ const message = row?.messages?.find(item => item.messageId === id)
74
+ if (!message) throw asrError('QQ_MESSAGE_SCOPE')
75
+
76
+ let segments
77
+ try {
78
+ segments = sanitizeInboundSegments(message.segments)
79
+ } catch {
80
+ throw asrError('QQ_NATIVE_ASR_MESSAGE_INVALID')
81
+ }
82
+ if (!segments.some(segment => segment.type === 'record')) throw asrError('QQ_NATIVE_ASR_NOT_RECORD')
83
+
84
+ let response
85
+ try {
86
+ response = await transport.action('fetch_ptt_text', { message_id: id }, PLATFORM_TIMEOUT_MS, MAX_RESPONSE_BYTES)
87
+ } catch (error) {
88
+ throw asrError(error?.code === 'ONEBOT_RESPONSE_TOO_LARGE'
89
+ ? 'QQ_NATIVE_ASR_RESPONSE_TOO_LARGE'
90
+ : 'QQ_NATIVE_ASR_UNAVAILABLE')
91
+ }
92
+
93
+ assertRead(core, sessionId, true)
94
+ if (!response || typeof response !== 'object' || Array.isArray(response)) {
95
+ throw asrError('QQ_NATIVE_ASR_INVALID_RESPONSE')
96
+ }
97
+ const text = boundedText(response.text)
98
+ assertRead(core, sessionId, true)
99
+
100
+ try {
101
+ store.setMessageTranscript(scene, id, text)
102
+ } catch {
103
+ throw asrError('QQ_NATIVE_ASR_STORAGE_FAILED')
104
+ }
105
+
106
+ return {
107
+ text,
108
+ messageId: id,
109
+ senderId: message.senderId,
110
+ scene: { botId: scene.botId, kind: scene.kind, peerId: scene.peerId },
111
+ }
112
+ }