@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.
- package/LICENSE +21 -21
- package/README.md +55 -53
- package/README.zh-CN.md +51 -51
- package/REFERENCE.md +49 -49
- package/cordis.patch.yml +6 -6
- package/docs/DATA_MIGRATION.md +26 -26
- package/docs/INSTALL_V1_2.md +22 -22
- package/docs/PUBLISHING.md +28 -26
- package/docs/RELEASE_CHECKLIST.md +23 -23
- package/docs/RELEASE_NOTES.md +38 -38
- package/docs/UPGRADE_POLICY.md +26 -26
- package/docs/verification/IMAGE_READ_FIX_2026-11-07.md +22 -0
- package/docs/verification/LIFE_QQ_BOUNDARY_2026-11-07.md +20 -0
- package/lib/client.js +372 -372
- package/package.json +94 -91
- package/preset.patch.yml +63 -0
- package/scripts/symlink-security.mjs +1 -1
- package/src/account-profile.js +223 -223
- package/src/admin-http.js +361 -361
- package/src/audio.js +428 -428
- package/src/capabilities.js +785 -785
- package/src/client/factory.template.js +82 -82
- package/src/client/logic.js +290 -290
- package/src/config.js +2 -0
- package/src/console/console.css +28 -28
- package/src/console/console.js +3 -0
- package/src/console/index.html +67 -67
- package/src/core.js +21 -4
- package/src/files.js +230 -230
- package/src/index.js +135 -8
- package/src/lease.js +42 -42
- package/src/media.js +66 -3
- package/src/napcat-action-names.js +186 -186
- package/src/native-asr.js +112 -112
- package/src/onebot.js +378 -378
- package/src/outbound-media.js +309 -309
- package/src/owner-workspace.js +394 -394
- package/src/permissions.js +20 -0
- package/src/preset-guard.mjs +16 -2
- package/src/qzone-provider.js +628 -628
- package/src/session-provenance.js +74 -74
- package/src/setup.js +255 -255
- package/src/web-console.js +9 -9
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { randomUUID } from 'node:crypto'
|
|
4
|
-
|
|
5
|
-
// This journal is separate from replaceable scene configuration. Never infer
|
|
6
|
-
// ordinary provenance from absence in a potentially incomplete historical index.
|
|
7
|
-
export class SessionProvenance {
|
|
8
|
-
constructor(file, { sessions, store, now = () => Date.now() }) {
|
|
9
|
-
this.file = file
|
|
10
|
-
this.sessions = sessions
|
|
11
|
-
this.store = store
|
|
12
|
-
this.now = now
|
|
13
|
-
this.observedSince = now()
|
|
14
|
-
this.pending = new Set()
|
|
15
|
-
this.state = fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, 'utf8')) :
|
|
16
|
-
{ version: 1, observedSince: now(), reserved: [] }
|
|
17
|
-
if (this.state.version !== 1 || !Number.isSafeInteger(this.state.observedSince) ||
|
|
18
|
-
!Array.isArray(this.state.reserved) || this.state.reserved.some(id => typeof id !== 'string')) {
|
|
19
|
-
throw new Error('QQ_PROVENANCE_INVALID: restore the provenance backup; refusing reset')
|
|
20
|
-
}
|
|
21
|
-
if (!fs.existsSync(file)) this.persist(this.state)
|
|
22
|
-
this.state.ordinary ??= {}
|
|
23
|
-
if (typeof this.state.ordinary !== 'object' || Array.isArray(this.state.ordinary) || this.state.ordinary === null) {
|
|
24
|
-
throw new Error('QQ_PROVENANCE_INVALID: invalid ordinary attestations')
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
persist(state) {
|
|
28
|
-
fs.mkdirSync(path.dirname(this.file), { recursive: true })
|
|
29
|
-
const temp = `${this.file}.${randomUUID()}.tmp`
|
|
30
|
-
const fd = fs.openSync(temp, 'wx', 0o600)
|
|
31
|
-
try { fs.writeFileSync(fd, JSON.stringify(state)); fs.fsyncSync(fd) } finally { fs.closeSync(fd) }
|
|
32
|
-
fs.renameSync(temp, this.file)
|
|
33
|
-
}
|
|
34
|
-
reserve() {
|
|
35
|
-
const id = `session-${randomUUID()}`
|
|
36
|
-
const next = { ...this.state, reserved: [...this.state.reserved, id] }
|
|
37
|
-
this.persist(next) // Must precede even the first Host create await.
|
|
38
|
-
this.state = next
|
|
39
|
-
this.pending.add(id)
|
|
40
|
-
return id
|
|
41
|
-
}
|
|
42
|
-
complete(id, returnedId) {
|
|
43
|
-
if (returnedId !== undefined && returnedId !== id) {
|
|
44
|
-
const next = { ...this.state, unsupportedHost: true }
|
|
45
|
-
this.persist(next)
|
|
46
|
-
this.state = next
|
|
47
|
-
}
|
|
48
|
-
this.pending.delete(id)
|
|
49
|
-
}
|
|
50
|
-
classify(sessionId) {
|
|
51
|
-
const session = this.sessions()?.get?.(sessionId)
|
|
52
|
-
if (!session || session.id !== sessionId) return { kind: 'unknown', reason: 'session-unavailable' }
|
|
53
|
-
if (this.store.isKnownSession(sessionId) || this.state.reserved.includes(sessionId)) {
|
|
54
|
-
return { kind: 'qq', reason: 'durable-qq-reservation' }
|
|
55
|
-
}
|
|
56
|
-
const raw = session.header?.createdAt
|
|
57
|
-
const created = typeof raw === 'number' ? raw : typeof raw === 'string' ? Date.parse(raw) : NaN
|
|
58
|
-
// Before journal enrollment, failed/unbound historical QQ creation is not
|
|
59
|
-
// reconstructible. Require a fresh Host Session instead of guessing.
|
|
60
|
-
if (Number.isFinite(created) && Object.hasOwn(this.state.ordinary, sessionId) && this.state.ordinary[sessionId] === created) {
|
|
61
|
-
return { kind: 'ordinary', reason: 'durable-host-attestation' }
|
|
62
|
-
}
|
|
63
|
-
if (this.pending.size || this.state.unsupportedHost) return { kind: 'unknown', reason: 'qq-creation-contract-unverified' }
|
|
64
|
-
// A previous process's observation interval is not evidence for Sessions
|
|
65
|
-
// created while it was absent (or an older connector was running).
|
|
66
|
-
if (!Number.isFinite(created) || created <= this.observedSince || created > this.now()) {
|
|
67
|
-
return { kind: 'unknown', reason: 'historical-provenance-unverified' }
|
|
68
|
-
}
|
|
69
|
-
const next = { ...this.state, ordinary: { ...this.state.ordinary, [sessionId]: created } }
|
|
70
|
-
this.persist(next)
|
|
71
|
-
this.state = next
|
|
72
|
-
return { kind: 'ordinary', reason: 'host-created-after-reservation-contract' }
|
|
73
|
-
}
|
|
74
|
-
}
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { randomUUID } from 'node:crypto'
|
|
4
|
+
|
|
5
|
+
// This journal is separate from replaceable scene configuration. Never infer
|
|
6
|
+
// ordinary provenance from absence in a potentially incomplete historical index.
|
|
7
|
+
export class SessionProvenance {
|
|
8
|
+
constructor(file, { sessions, store, now = () => Date.now() }) {
|
|
9
|
+
this.file = file
|
|
10
|
+
this.sessions = sessions
|
|
11
|
+
this.store = store
|
|
12
|
+
this.now = now
|
|
13
|
+
this.observedSince = now()
|
|
14
|
+
this.pending = new Set()
|
|
15
|
+
this.state = fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, 'utf8')) :
|
|
16
|
+
{ version: 1, observedSince: now(), reserved: [] }
|
|
17
|
+
if (this.state.version !== 1 || !Number.isSafeInteger(this.state.observedSince) ||
|
|
18
|
+
!Array.isArray(this.state.reserved) || this.state.reserved.some(id => typeof id !== 'string')) {
|
|
19
|
+
throw new Error('QQ_PROVENANCE_INVALID: restore the provenance backup; refusing reset')
|
|
20
|
+
}
|
|
21
|
+
if (!fs.existsSync(file)) this.persist(this.state)
|
|
22
|
+
this.state.ordinary ??= {}
|
|
23
|
+
if (typeof this.state.ordinary !== 'object' || Array.isArray(this.state.ordinary) || this.state.ordinary === null) {
|
|
24
|
+
throw new Error('QQ_PROVENANCE_INVALID: invalid ordinary attestations')
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
persist(state) {
|
|
28
|
+
fs.mkdirSync(path.dirname(this.file), { recursive: true })
|
|
29
|
+
const temp = `${this.file}.${randomUUID()}.tmp`
|
|
30
|
+
const fd = fs.openSync(temp, 'wx', 0o600)
|
|
31
|
+
try { fs.writeFileSync(fd, JSON.stringify(state)); fs.fsyncSync(fd) } finally { fs.closeSync(fd) }
|
|
32
|
+
fs.renameSync(temp, this.file)
|
|
33
|
+
}
|
|
34
|
+
reserve() {
|
|
35
|
+
const id = `session-${randomUUID()}`
|
|
36
|
+
const next = { ...this.state, reserved: [...this.state.reserved, id] }
|
|
37
|
+
this.persist(next) // Must precede even the first Host create await.
|
|
38
|
+
this.state = next
|
|
39
|
+
this.pending.add(id)
|
|
40
|
+
return id
|
|
41
|
+
}
|
|
42
|
+
complete(id, returnedId) {
|
|
43
|
+
if (returnedId !== undefined && returnedId !== id) {
|
|
44
|
+
const next = { ...this.state, unsupportedHost: true }
|
|
45
|
+
this.persist(next)
|
|
46
|
+
this.state = next
|
|
47
|
+
}
|
|
48
|
+
this.pending.delete(id)
|
|
49
|
+
}
|
|
50
|
+
classify(sessionId) {
|
|
51
|
+
const session = this.sessions()?.get?.(sessionId)
|
|
52
|
+
if (!session || session.id !== sessionId) return { kind: 'unknown', reason: 'session-unavailable' }
|
|
53
|
+
if (this.store.isKnownSession(sessionId) || this.state.reserved.includes(sessionId)) {
|
|
54
|
+
return { kind: 'qq', reason: 'durable-qq-reservation' }
|
|
55
|
+
}
|
|
56
|
+
const raw = session.header?.createdAt
|
|
57
|
+
const created = typeof raw === 'number' ? raw : typeof raw === 'string' ? Date.parse(raw) : NaN
|
|
58
|
+
// Before journal enrollment, failed/unbound historical QQ creation is not
|
|
59
|
+
// reconstructible. Require a fresh Host Session instead of guessing.
|
|
60
|
+
if (Number.isFinite(created) && Object.hasOwn(this.state.ordinary, sessionId) && this.state.ordinary[sessionId] === created) {
|
|
61
|
+
return { kind: 'ordinary', reason: 'durable-host-attestation' }
|
|
62
|
+
}
|
|
63
|
+
if (this.pending.size || this.state.unsupportedHost) return { kind: 'unknown', reason: 'qq-creation-contract-unverified' }
|
|
64
|
+
// A previous process's observation interval is not evidence for Sessions
|
|
65
|
+
// created while it was absent (or an older connector was running).
|
|
66
|
+
if (!Number.isFinite(created) || created <= this.observedSince || created > this.now()) {
|
|
67
|
+
return { kind: 'unknown', reason: 'historical-provenance-unverified' }
|
|
68
|
+
}
|
|
69
|
+
const next = { ...this.state, ordinary: { ...this.state.ordinary, [sessionId]: created } }
|
|
70
|
+
this.persist(next)
|
|
71
|
+
this.state = next
|
|
72
|
+
return { kind: 'ordinary', reason: 'host-created-after-reservation-contract' }
|
|
73
|
+
}
|
|
74
|
+
}
|