@zhin.js/adapter-qq 1.1.22 → 1.1.23

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/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @zhin.js/adapter-qq
2
2
 
3
+ ## 1.1.23
4
+
5
+ ### Patch Changes
6
+
7
+ - bc6ccb1: Deep audit bug fixes and 7 architectural improvements:
8
+ - Sink Agent Turn ingress pipeline from `@zhin.js/cli` into `@zhin.js/agent/runtime` (`plugin-runtime/ingress/`) and decompose `ingress-route.ts` into modular pipeline stages.
9
+ - Bind Session State Plane (`JsxButtonRegistry`, `InteractionRuntime`, `RuntimeInteractiveRouter`) to `PluginIncarnationRef` so active buttons and interactions survive unrelated-plugin HMR while expiring when the owning plugin reloads, and support per-conversation fallback numbering (`numberingScope: 'conversation'`).
10
+ - Establish `conversation_events` as the canonical message SSOT and reference `conversation_event_id`, `conversation_key`, `platform_message_id`, and `message_key` in `agent_messages` (`AGENT_MESSAGE_QUERY_VERSION = 2`), threading `conversationSequence` across inbound and outbound delivery receipts.
11
+ - Push down `DatabaseContextRepository` and `DatabaseScheduleJobStorage` full-session/full-table memory scans to indexed SQL queries.
12
+ - Add kernel-level inbound `replyTo` and `mentioned` auto-promotion (`promoteInboundMessagePayload`) plus reusable `InboundDeduper` and `TtlLookupCache` primitives in `@zhin.js/adapter`.
13
+ - Add `MiddlewareContext.dispatch` (`InboundDispatchSummary`) and `onAfterDispatch` hooks for `after-dispatch` middlewares, and support incremental rendering of in-place `envelope.payload` array mutations in `OutboundDeliveryRuntime`.
14
+ - Unify `HistoryWindowTracker` and `AgentCompactionRuntime` token/message budgets (`resolveUnifiedHistoryAndCompactionBudget`).
15
+ - Fix schema validation, database transaction connection cleanup and SQLite WAL mode, schedule timer wheel head-of-line blocking, security policy bash read paths and subagent guard propagation, group merge window permission carrier handoff, micro-compact namespaced tool matching, and WebSocket force-close / inbound segment mapping across adapters.
16
+ - Updated dependencies [3a8504b]
17
+ - Updated dependencies [6163abc]
18
+ - Updated dependencies [fed2c27]
19
+ - Updated dependencies [bc6ccb1]
20
+ - Updated dependencies [72b5a12]
21
+ - Updated dependencies [aa41889]
22
+ - Updated dependencies [4427e72]
23
+ - Updated dependencies [22bd14a]
24
+ - @zhin.js/agent-feature@1.1.14
25
+ - @zhin.js/core@1.1.57
26
+ - @zhin.js/client@1.1.25
27
+ - @zhin.js/page@1.1.15
28
+ - @zhin.js/im-contract@1.1.12
29
+ - @zhin.js/adapter@1.1.29
30
+ - @zhin.js/host-http@1.1.15
31
+ - @zhin.js/feature-kit@1.1.13
32
+ - @zhin.js/tool@1.1.16
33
+ - @zhin.js/adapter-onebot-events@0.0.2
34
+ - @zhin.js/permission@1.1.13
35
+ - @zhin.js/skill@1.1.14
36
+
3
37
  ## 1.1.22
4
38
 
5
39
  ### Patch Changes
@@ -16,6 +16,8 @@ export type ImageProbeFetch = (url: string, init: {
16
16
  }>;
17
17
  /** 从图片文件头解析尺寸(PNG / GIF / JPEG / WebP)。 */
18
18
  export declare function imageSizeFromBytes(bytes: Uint8Array): QqImageSize | undefined;
19
+ /** 校验公网 HTTP(S) URL,拒绝内网/回环/元数据地址以防 SSRF。 */
20
+ export declare function isSafePublicImageUrl(rawUrl: string): boolean;
19
21
  /** 读取公网图片文件头得到尺寸;网络错误、超时或格式不识别时返回 undefined。 */
20
22
  export interface ImageProbeOptions {
21
23
  readonly fetch?: ImageProbeFetch;
package/lib/image-size.js CHANGED
@@ -82,7 +82,51 @@ async function readHead(response) {
82
82
  }
83
83
  return out;
84
84
  }
85
+ /** 校验公网 HTTP(S) URL,拒绝内网/回环/元数据地址以防 SSRF。 */
86
+ export function isSafePublicImageUrl(rawUrl) {
87
+ let parsed;
88
+ try {
89
+ parsed = new URL(rawUrl);
90
+ }
91
+ catch {
92
+ return false;
93
+ }
94
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
95
+ return false;
96
+ const host = parsed.hostname.replace(/^\[|\]$/g, '').toLowerCase();
97
+ if (!host || host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local') || host.endsWith('.internal')) {
98
+ return false;
99
+ }
100
+ if (host === '::1'
101
+ || host === '0:0:0:0:0:0:0:1'
102
+ || host === '::'
103
+ || host.startsWith('fe80:')
104
+ || host.startsWith('fc')
105
+ || host.startsWith('fd')
106
+ || host.startsWith('::ffff:127.')
107
+ || host.startsWith('::ffff:10.')
108
+ || host.startsWith('::ffff:192.168.')
109
+ || host.startsWith('::ffff:169.254.')) {
110
+ return false;
111
+ }
112
+ const ipv4Match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
113
+ if (ipv4Match) {
114
+ const [a, b] = [Number(ipv4Match[1]), Number(ipv4Match[2])];
115
+ if (a === 0
116
+ || a === 10
117
+ || a === 127
118
+ || (a === 169 && b === 254)
119
+ || (a === 172 && b >= 16 && b <= 31)
120
+ || (a === 192 && b === 168)
121
+ || (a === 100 && b >= 64 && b <= 127)) {
122
+ return false;
123
+ }
124
+ }
125
+ return true;
126
+ }
85
127
  export async function probeImageSize(url, { fetch: fetchImpl = fetch, timeoutMs = PROBE_TIMEOUT_MS, signal } = {}) {
128
+ if (!isSafePublicImageUrl(url))
129
+ return undefined;
86
130
  try {
87
131
  const response = await fetchImpl(url, {
88
132
  headers: { Range: `bytes=0-${PROBE_BYTES - 1}` },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-qq",
3
- "version": "1.1.22",
3
+ "version": "1.1.23",
4
4
  "description": "Zhin.js QQ Official adapter for Plugin Runtime (WebSocket gateway)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -34,28 +34,28 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "qq-official-bot": "^1.3.3",
37
- "@zhin.js/adapter-onebot-events": "0.0.1",
38
- "@zhin.js/adapter": "1.1.28",
39
- "@zhin.js/agent-feature": "1.1.13",
40
- "@zhin.js/client": "1.1.24",
37
+ "@zhin.js/adapter-onebot-events": "0.0.2",
38
+ "@zhin.js/adapter": "1.1.29",
39
+ "@zhin.js/agent-feature": "1.1.14",
40
+ "@zhin.js/client": "1.1.25",
41
41
  "@zhin.js/console-contract": "1.1.3",
42
- "@zhin.js/core": "1.1.56",
43
- "@zhin.js/feature-kit": "1.1.12",
44
- "@zhin.js/host-http": "1.1.14",
45
- "@zhin.js/im-contract": "1.1.11",
42
+ "@zhin.js/core": "1.1.57",
43
+ "@zhin.js/feature-kit": "1.1.13",
44
+ "@zhin.js/host-http": "1.1.15",
45
+ "@zhin.js/im-contract": "1.1.12",
46
46
  "@zhin.js/logger": "1.1.2",
47
- "@zhin.js/page": "1.1.14",
48
- "@zhin.js/permission": "1.1.12",
49
- "@zhin.js/skill": "1.1.13",
50
- "@zhin.js/tool": "1.1.15"
47
+ "@zhin.js/page": "1.1.15",
48
+ "@zhin.js/permission": "1.1.13",
49
+ "@zhin.js/skill": "1.1.14",
50
+ "@zhin.js/tool": "1.1.16"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "zod": "^4.0.0",
54
- "@zhin.js/adapter": "^1.1.28",
55
- "@zhin.js/command": "^1.1.14",
56
- "@zhin.js/core": "^1.1.56",
57
- "@zhin.js/middleware": "^1.1.13",
58
- "zhin.js": "^1.1.21"
54
+ "@zhin.js/adapter": "^1.1.29",
55
+ "@zhin.js/command": "^1.1.15",
56
+ "@zhin.js/core": "^1.1.57",
57
+ "@zhin.js/middleware": "^1.1.14",
58
+ "zhin.js": "^1.1.22"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "@zhin.js/command": {
@@ -76,8 +76,8 @@
76
76
  "typescript": "^6.0.3",
77
77
  "vitest": "^4.1.10",
78
78
  "zod": "^4.4.3",
79
- "@zhin.js/host-http": "1.1.14",
80
- "zhin.js": "1.1.21"
79
+ "@zhin.js/host-http": "1.1.15",
80
+ "zhin.js": "1.1.22"
81
81
  },
82
82
  "files": [
83
83
  "adapters",
package/src/image-size.ts CHANGED
@@ -91,6 +91,51 @@ async function readHead(response: Awaited<ReturnType<ImageProbeFetch>>): Promise
91
91
  return out;
92
92
  }
93
93
 
94
+ /** 校验公网 HTTP(S) URL,拒绝内网/回环/元数据地址以防 SSRF。 */
95
+ export function isSafePublicImageUrl(rawUrl: string): boolean {
96
+ let parsed: URL;
97
+ try {
98
+ parsed = new URL(rawUrl);
99
+ } catch {
100
+ return false;
101
+ }
102
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;
103
+ const host = parsed.hostname.replace(/^\[|\]$/g, '').toLowerCase();
104
+ if (!host || host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local') || host.endsWith('.internal')) {
105
+ return false;
106
+ }
107
+ if (
108
+ host === '::1'
109
+ || host === '0:0:0:0:0:0:0:1'
110
+ || host === '::'
111
+ || host.startsWith('fe80:')
112
+ || host.startsWith('fc')
113
+ || host.startsWith('fd')
114
+ || host.startsWith('::ffff:127.')
115
+ || host.startsWith('::ffff:10.')
116
+ || host.startsWith('::ffff:192.168.')
117
+ || host.startsWith('::ffff:169.254.')
118
+ ) {
119
+ return false;
120
+ }
121
+ const ipv4Match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
122
+ if (ipv4Match) {
123
+ const [a, b] = [Number(ipv4Match[1]), Number(ipv4Match[2])];
124
+ if (
125
+ a === 0
126
+ || a === 10
127
+ || a === 127
128
+ || (a === 169 && b === 254)
129
+ || (a === 172 && b >= 16 && b <= 31)
130
+ || (a === 192 && b === 168)
131
+ || (a === 100 && b >= 64 && b <= 127)
132
+ ) {
133
+ return false;
134
+ }
135
+ }
136
+ return true;
137
+ }
138
+
94
139
  /** 读取公网图片文件头得到尺寸;网络错误、超时或格式不识别时返回 undefined。 */
95
140
  export interface ImageProbeOptions {
96
141
  readonly fetch?: ImageProbeFetch;
@@ -101,6 +146,7 @@ export async function probeImageSize(
101
146
  url: string,
102
147
  { fetch: fetchImpl = fetch as unknown as ImageProbeFetch, timeoutMs = PROBE_TIMEOUT_MS, signal }: ImageProbeOptions = {},
103
148
  ): Promise<QqImageSize | undefined> {
149
+ if (!isSafePublicImageUrl(url)) return undefined;
104
150
  try {
105
151
  const response = await fetchImpl(url, {
106
152
  headers: { Range: `bytes=0-${PROBE_BYTES - 1}` },