@agentunion/fastaun 0.2.14 → 0.2.15
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/client.d.ts +4 -0
- package/dist/client.js +137 -35
- package/dist/client.js.map +1 -1
- package/dist/e2ee-group.d.ts +23 -2
- package/dist/e2ee-group.js +194 -23
- package/dist/e2ee-group.js.map +1 -1
- package/dist/e2ee.d.ts +20 -1
- package/dist/e2ee.js +258 -35
- package/dist/e2ee.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/keystore/file.d.ts +10 -0
- package/dist/keystore/file.js +73 -0
- package/dist/keystore/file.js.map +1 -1
- package/dist/keystore/index.d.ts +12 -0
- package/dist/namespaces/auth.d.ts +19 -0
- package/dist/namespaces/auth.js +185 -0
- package/dist/namespaces/auth.js.map +1 -1
- package/dist/namespaces/meta.d.ts +75 -0
- package/dist/namespaces/meta.js +464 -0
- package/dist/namespaces/meta.js.map +1 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { GroupE2EEManager } from './e2ee-group.js';
|
|
|
15
15
|
import { type Subscription, type EventHandler } from './events.js';
|
|
16
16
|
import { AuthNamespace } from './namespaces/auth.js';
|
|
17
17
|
import { CustodyNamespace } from './namespaces/custody.js';
|
|
18
|
+
import { MetaNamespace } from './namespaces/meta.js';
|
|
18
19
|
import { type JsonValue, type RpcParams, type RpcResult } from './types.js';
|
|
19
20
|
/**
|
|
20
21
|
* 递归排序键的 JSON 序列化(Canonical JSON for AUN)
|
|
@@ -58,6 +59,8 @@ export declare class AUNClient {
|
|
|
58
59
|
readonly auth: AuthNamespace;
|
|
59
60
|
/** AID 托管命名空间 */
|
|
60
61
|
readonly custody: CustodyNamespace;
|
|
62
|
+
/** Meta 命名空间(心跳、状态、信任根管理) */
|
|
63
|
+
readonly meta: MetaNamespace;
|
|
61
64
|
/** 会话参数(重连用) */
|
|
62
65
|
private _sessionParams;
|
|
63
66
|
/** 会话选项 */
|
|
@@ -149,6 +152,7 @@ export declare class AUNClient {
|
|
|
149
152
|
on(event: string, handler: EventHandler): Subscription;
|
|
150
153
|
/** P2-13: 取消订阅事件(对齐 Python/JS off 方法) */
|
|
151
154
|
off(event: string, handler: EventHandler): void;
|
|
155
|
+
private _protectedHeadersFromParams;
|
|
152
156
|
/** 自动加密并发送 P2P 消息 */
|
|
153
157
|
private _sendEncrypted;
|
|
154
158
|
private _sendEncryptedSingle;
|
package/dist/client.js
CHANGED
|
@@ -27,6 +27,7 @@ import { AUNLogger } from './logger.js';
|
|
|
27
27
|
import { SQLiteBackup } from './keystore/sqlite-backup.js';
|
|
28
28
|
import { AuthNamespace } from './namespaces/auth.js';
|
|
29
29
|
import { CustodyNamespace } from './namespaces/custody.js';
|
|
30
|
+
import { MetaNamespace } from './namespaces/meta.js';
|
|
30
31
|
import { RPCTransport } from './transport.js';
|
|
31
32
|
import { AuthFlow } from './auth.js';
|
|
32
33
|
import { SeqTracker } from './seq-tracker.js';
|
|
@@ -141,6 +142,7 @@ const SIGNED_METHODS = new Set([
|
|
|
141
142
|
]);
|
|
142
143
|
/** peer 证书缓存 TTL(10 分钟) */
|
|
143
144
|
const PEER_CERT_CACHE_TTL = 600;
|
|
145
|
+
const PREKEY_FALLBACK_DEVICE_ID = 'aun_device_id';
|
|
144
146
|
function isGroupServiceAid(value) {
|
|
145
147
|
const text = String(value ?? '').trim();
|
|
146
148
|
if (!text.includes('.'))
|
|
@@ -165,6 +167,52 @@ function isPeerPrekeyResponse(value) {
|
|
|
165
167
|
return false;
|
|
166
168
|
return candidate.prekey === undefined || isPeerPrekeyMaterial(candidate.prekey);
|
|
167
169
|
}
|
|
170
|
+
function normalizePeerPrekeys(prekeys) {
|
|
171
|
+
const normalized = [];
|
|
172
|
+
for (const item of prekeys) {
|
|
173
|
+
if (!isPeerPrekeyMaterial(item))
|
|
174
|
+
continue;
|
|
175
|
+
const prekeyId = item.prekey_id.trim();
|
|
176
|
+
const publicKey = item.public_key.trim();
|
|
177
|
+
const signature = item.signature.trim();
|
|
178
|
+
if (!prekeyId || !publicKey || !signature)
|
|
179
|
+
continue;
|
|
180
|
+
const deviceId = String(item.device_id ?? '').trim();
|
|
181
|
+
const certFingerprint = String(item.cert_fingerprint ?? '').trim().toLowerCase();
|
|
182
|
+
const candidate = {
|
|
183
|
+
...item,
|
|
184
|
+
prekey_id: prekeyId,
|
|
185
|
+
public_key: publicKey,
|
|
186
|
+
signature,
|
|
187
|
+
device_id: deviceId,
|
|
188
|
+
};
|
|
189
|
+
if (certFingerprint) {
|
|
190
|
+
candidate.cert_fingerprint = certFingerprint;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
delete candidate.cert_fingerprint;
|
|
194
|
+
}
|
|
195
|
+
normalized.push(candidate);
|
|
196
|
+
}
|
|
197
|
+
if (normalized.length === 0)
|
|
198
|
+
return [];
|
|
199
|
+
if (normalized.length === 1) {
|
|
200
|
+
if (!String(normalized[0].device_id ?? '').trim()) {
|
|
201
|
+
normalized[0].device_id = PREKEY_FALLBACK_DEVICE_ID;
|
|
202
|
+
}
|
|
203
|
+
return normalized;
|
|
204
|
+
}
|
|
205
|
+
const seen = new Set();
|
|
206
|
+
const filtered = [];
|
|
207
|
+
for (const item of normalized) {
|
|
208
|
+
const deviceId = String(item.device_id ?? '').trim();
|
|
209
|
+
if (!deviceId || deviceId === PREKEY_FALLBACK_DEVICE_ID || seen.has(deviceId))
|
|
210
|
+
continue;
|
|
211
|
+
seen.add(deviceId);
|
|
212
|
+
filtered.push(item);
|
|
213
|
+
}
|
|
214
|
+
return filtered;
|
|
215
|
+
}
|
|
168
216
|
function formatCaughtError(error) {
|
|
169
217
|
return error instanceof Error ? error : String(error);
|
|
170
218
|
}
|
|
@@ -271,6 +319,8 @@ export class AUNClient {
|
|
|
271
319
|
auth;
|
|
272
320
|
/** AID 托管命名空间 */
|
|
273
321
|
custody;
|
|
322
|
+
/** Meta 命名空间(心跳、状态、信任根管理) */
|
|
323
|
+
meta;
|
|
274
324
|
/** 会话参数(重连用) */
|
|
275
325
|
_sessionParams = null;
|
|
276
326
|
/** 会话选项 */
|
|
@@ -368,6 +418,7 @@ export class AUNClient {
|
|
|
368
418
|
});
|
|
369
419
|
this.auth = new AuthNamespace(this);
|
|
370
420
|
this.custody = new CustodyNamespace(this);
|
|
421
|
+
this.meta = new MetaNamespace(this);
|
|
371
422
|
// 内部订阅:推送消息自动解密后 re-publish 给用户
|
|
372
423
|
this._dispatcher.subscribe('_raw.message.received', (data) => this._onRawMessageReceived(data));
|
|
373
424
|
// 群组消息推送:自动解密后 re-publish
|
|
@@ -518,6 +569,8 @@ export class AUNClient {
|
|
|
518
569
|
if (encrypt) {
|
|
519
570
|
return await this._sendEncrypted(p);
|
|
520
571
|
}
|
|
572
|
+
delete p.protected_headers;
|
|
573
|
+
delete p.headers;
|
|
521
574
|
}
|
|
522
575
|
// 自动加密:group.send 默认加密(encrypt 默认 True)
|
|
523
576
|
if (method === 'group.send') {
|
|
@@ -526,6 +579,8 @@ export class AUNClient {
|
|
|
526
579
|
if (encrypt) {
|
|
527
580
|
return await this._sendGroupEncrypted(p);
|
|
528
581
|
}
|
|
582
|
+
delete p.protected_headers;
|
|
583
|
+
delete p.headers;
|
|
529
584
|
}
|
|
530
585
|
if (method === 'group.thought.put') {
|
|
531
586
|
const encrypt = p.encrypt ?? true;
|
|
@@ -698,6 +753,17 @@ export class AUNClient {
|
|
|
698
753
|
this._dispatcher.unsubscribe(event, handler);
|
|
699
754
|
}
|
|
700
755
|
// ── E2EE 加密发送 ────────────────────────────────────────
|
|
756
|
+
_protectedHeadersFromParams(params) {
|
|
757
|
+
const value = params.protected_headers ?? params.headers;
|
|
758
|
+
if (value == null)
|
|
759
|
+
return null;
|
|
760
|
+
if (isJsonObject(value))
|
|
761
|
+
return value;
|
|
762
|
+
if (typeof value === 'object' && typeof value.toObject === 'function') {
|
|
763
|
+
return value;
|
|
764
|
+
}
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
701
767
|
/** 自动加密并发送 P2P 消息 */
|
|
702
768
|
async _sendEncrypted(params) {
|
|
703
769
|
const toAid = String(params.to ?? '');
|
|
@@ -709,6 +775,7 @@ export class AUNClient {
|
|
|
709
775
|
throw new ValidationError('message.send payload must be an object when encrypt=true');
|
|
710
776
|
}
|
|
711
777
|
const persistRequired = Boolean(params.persist_required || params.durable);
|
|
778
|
+
const protectedHeaders = this._protectedHeadersFromParams(params);
|
|
712
779
|
// 惰性同步:首次发送 P2P 消息时先 pull 一次
|
|
713
780
|
if (!this._p2pSynced) {
|
|
714
781
|
await this._lazySyncP2p();
|
|
@@ -719,6 +786,7 @@ export class AUNClient {
|
|
|
719
786
|
payload,
|
|
720
787
|
messageId,
|
|
721
788
|
timestamp,
|
|
789
|
+
protectedHeaders,
|
|
722
790
|
});
|
|
723
791
|
if (recipientPrekeys.length <= 1 && selfSyncCopies.length === 0) {
|
|
724
792
|
return await this._sendEncryptedSingle({
|
|
@@ -728,6 +796,7 @@ export class AUNClient {
|
|
|
728
796
|
timestamp,
|
|
729
797
|
prekey: recipientPrekeys[0],
|
|
730
798
|
persistRequired,
|
|
799
|
+
protectedHeaders,
|
|
731
800
|
});
|
|
732
801
|
}
|
|
733
802
|
const recipientCopies = await this._buildRecipientDeviceCopies({
|
|
@@ -736,6 +805,7 @@ export class AUNClient {
|
|
|
736
805
|
messageId,
|
|
737
806
|
timestamp,
|
|
738
807
|
prekeys: recipientPrekeys,
|
|
808
|
+
protectedHeaders,
|
|
739
809
|
});
|
|
740
810
|
const sendParams = {
|
|
741
811
|
to: toAid,
|
|
@@ -769,6 +839,7 @@ export class AUNClient {
|
|
|
769
839
|
prekey,
|
|
770
840
|
messageId: opts.messageId,
|
|
771
841
|
timestamp: opts.timestamp,
|
|
842
|
+
protectedHeaders: opts.protectedHeaders,
|
|
772
843
|
});
|
|
773
844
|
this._ensureEncryptResult(opts.toAid, encryptResult);
|
|
774
845
|
const sendParams = {
|
|
@@ -787,7 +858,7 @@ export class AUNClient {
|
|
|
787
858
|
async _buildRecipientDeviceCopies(opts) {
|
|
788
859
|
const recipientCopies = [];
|
|
789
860
|
const certCache = new Map();
|
|
790
|
-
for (const prekey of opts.prekeys) {
|
|
861
|
+
for (const prekey of normalizePeerPrekeys(opts.prekeys)) {
|
|
791
862
|
const deviceId = String(prekey.device_id ?? '').trim();
|
|
792
863
|
const peerCertFingerprint = String(prekey.cert_fingerprint ?? '').trim().toLowerCase();
|
|
793
864
|
const cacheKey = peerCertFingerprint || '__default__';
|
|
@@ -803,6 +874,7 @@ export class AUNClient {
|
|
|
803
874
|
prekey,
|
|
804
875
|
messageId: opts.messageId,
|
|
805
876
|
timestamp: opts.timestamp,
|
|
877
|
+
protectedHeaders: opts.protectedHeaders,
|
|
806
878
|
});
|
|
807
879
|
this._ensureEncryptResult(opts.toAid, encryptResult);
|
|
808
880
|
recipientCopies.push({
|
|
@@ -845,7 +917,7 @@ export class AUNClient {
|
|
|
845
917
|
if (!myAid) {
|
|
846
918
|
return [];
|
|
847
919
|
}
|
|
848
|
-
const prekeys = await this._fetchPeerPrekeys(myAid);
|
|
920
|
+
const prekeys = normalizePeerPrekeys(await this._fetchPeerPrekeys(myAid));
|
|
849
921
|
if (prekeys.length === 0) {
|
|
850
922
|
return [];
|
|
851
923
|
}
|
|
@@ -863,6 +935,7 @@ export class AUNClient {
|
|
|
863
935
|
prekey,
|
|
864
936
|
messageId: opts.messageId,
|
|
865
937
|
timestamp: opts.timestamp,
|
|
938
|
+
protectedHeaders: opts.protectedHeaders,
|
|
866
939
|
});
|
|
867
940
|
this._ensureEncryptResult(myAid, encryptResult);
|
|
868
941
|
copies.push({
|
|
@@ -873,7 +946,7 @@ export class AUNClient {
|
|
|
873
946
|
return copies;
|
|
874
947
|
}
|
|
875
948
|
_encryptCopyPayload(opts) {
|
|
876
|
-
const [envelope, encryptResult] = this._e2ee.encryptOutbound(opts.logicalToAid, opts.payload, opts.peerCertPem, opts.prekey ?? null, opts.messageId, opts.timestamp);
|
|
949
|
+
const [envelope, encryptResult] = this._e2ee.encryptOutbound(opts.logicalToAid, opts.payload, opts.peerCertPem, opts.prekey ?? null, opts.messageId, opts.timestamp, opts.protectedHeaders, opts.context ?? null);
|
|
877
950
|
return [envelope, encryptResult];
|
|
878
951
|
}
|
|
879
952
|
_ensureEncryptResult(toAid, encryptResult) {
|
|
@@ -905,7 +978,7 @@ export class AUNClient {
|
|
|
905
978
|
return await this._callGroupEncryptedRpc('group.thought.put', params, {
|
|
906
979
|
idField: 'thought_id',
|
|
907
980
|
idPrefix: 'gt',
|
|
908
|
-
extraFields: ['
|
|
981
|
+
extraFields: ['context'],
|
|
909
982
|
});
|
|
910
983
|
}
|
|
911
984
|
async _putMessageThoughtEncrypted(params) {
|
|
@@ -930,6 +1003,8 @@ export class AUNClient {
|
|
|
930
1003
|
prekey,
|
|
931
1004
|
messageId: thoughtId,
|
|
932
1005
|
timestamp,
|
|
1006
|
+
protectedHeaders: this._protectedHeadersFromParams(params),
|
|
1007
|
+
context: isJsonObject(params.context) ? params.context : null,
|
|
933
1008
|
});
|
|
934
1009
|
this._ensureEncryptResult(toAid, encryptResult);
|
|
935
1010
|
const sendParams = {
|
|
@@ -939,8 +1014,9 @@ export class AUNClient {
|
|
|
939
1014
|
encrypted: true,
|
|
940
1015
|
thought_id: thoughtId,
|
|
941
1016
|
timestamp,
|
|
942
|
-
reply_to: params.reply_to,
|
|
943
1017
|
};
|
|
1018
|
+
if ('context' in params)
|
|
1019
|
+
sendParams.context = params.context;
|
|
944
1020
|
this._signClientOperation('message.thought.put', sendParams);
|
|
945
1021
|
return await this._transport.call('message.thought.put', sendParams);
|
|
946
1022
|
}
|
|
@@ -977,12 +1053,26 @@ export class AUNClient {
|
|
|
977
1053
|
await this._waitForGroupMembershipEpochFloor(groupId, 2000);
|
|
978
1054
|
const epochResult = await this._committedGroupEpochState(groupId);
|
|
979
1055
|
const committedEpoch = Number(epochResult.committed_epoch ?? epochResult.epoch ?? 0);
|
|
980
|
-
const envelope = committedEpoch > 0
|
|
981
|
-
? this._groupE2ee.encryptWithEpoch(groupId, await this._ensureCommittedGroupSecretForSend(groupId, committedEpoch, epochResult), payload)
|
|
982
|
-
: await this._groupE2ee.encrypt(groupId, payload);
|
|
983
1056
|
const operationId = String(params[options.idField] ?? '').trim()
|
|
984
1057
|
|| `${options.idPrefix}-${crypto.randomUUID()}`;
|
|
985
1058
|
const timestamp = Number(params.timestamp ?? Date.now());
|
|
1059
|
+
const protectedHeaders = this._protectedHeadersFromParams(params);
|
|
1060
|
+
const context = method === 'group.thought.put' && isJsonObject(params.context)
|
|
1061
|
+
? params.context
|
|
1062
|
+
: null;
|
|
1063
|
+
const envelope = committedEpoch > 0
|
|
1064
|
+
? this._groupE2ee.encryptWithEpoch(groupId, await this._ensureCommittedGroupSecretForSend(groupId, committedEpoch, epochResult), payload, {
|
|
1065
|
+
messageId: operationId,
|
|
1066
|
+
timestamp,
|
|
1067
|
+
protectedHeaders,
|
|
1068
|
+
context,
|
|
1069
|
+
})
|
|
1070
|
+
: await this._groupE2ee.encrypt(groupId, payload, {
|
|
1071
|
+
messageId: operationId,
|
|
1072
|
+
timestamp,
|
|
1073
|
+
protectedHeaders,
|
|
1074
|
+
context,
|
|
1075
|
+
});
|
|
986
1076
|
const sendParams = {
|
|
987
1077
|
group_id: groupId,
|
|
988
1078
|
payload: envelope,
|
|
@@ -2416,11 +2506,17 @@ export class AUNClient {
|
|
|
2416
2506
|
async _fetchPeerPrekeys(peerAid) {
|
|
2417
2507
|
const cachedList = this._peerPrekeysCache.get(peerAid);
|
|
2418
2508
|
if (cachedList && Date.now() / 1000 < cachedList.expireAt) {
|
|
2419
|
-
|
|
2509
|
+
const normalized = normalizePeerPrekeys(cachedList.items);
|
|
2510
|
+
if (normalized.length > 0) {
|
|
2511
|
+
return normalized.map((item) => ({ ...item }));
|
|
2512
|
+
}
|
|
2420
2513
|
}
|
|
2421
2514
|
const cached = this._e2ee.getCachedPrekey(peerAid);
|
|
2422
|
-
if (cached !== null)
|
|
2423
|
-
|
|
2515
|
+
if (cached !== null) {
|
|
2516
|
+
const normalized = normalizePeerPrekeys([cached]);
|
|
2517
|
+
if (normalized.length > 0)
|
|
2518
|
+
return normalized.map((item) => ({ ...item }));
|
|
2519
|
+
}
|
|
2424
2520
|
try {
|
|
2425
2521
|
const result = await this._transport.call('message.e2ee.get_prekey', { aid: peerAid });
|
|
2426
2522
|
if (!isJsonObject(result)) {
|
|
@@ -2431,13 +2527,7 @@ export class AUNClient {
|
|
|
2431
2527
|
}
|
|
2432
2528
|
const devicePrekeys = Array.isArray(result.device_prekeys) ? result.device_prekeys : null;
|
|
2433
2529
|
if (devicePrekeys) {
|
|
2434
|
-
const normalized =
|
|
2435
|
-
for (const item of devicePrekeys) {
|
|
2436
|
-
if (!isPeerPrekeyMaterial(item)) {
|
|
2437
|
-
continue;
|
|
2438
|
-
}
|
|
2439
|
-
normalized.push({ ...item });
|
|
2440
|
-
}
|
|
2530
|
+
const normalized = normalizePeerPrekeys(devicePrekeys);
|
|
2441
2531
|
if (normalized.length > 0) {
|
|
2442
2532
|
this._peerPrekeysCache.set(peerAid, {
|
|
2443
2533
|
items: normalized.map((item) => ({ ...item })),
|
|
@@ -2452,12 +2542,15 @@ export class AUNClient {
|
|
|
2452
2542
|
}
|
|
2453
2543
|
const prekey = result.prekey;
|
|
2454
2544
|
if (prekey) {
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2545
|
+
const normalized = normalizePeerPrekeys([prekey]);
|
|
2546
|
+
if (normalized.length > 0) {
|
|
2547
|
+
this._peerPrekeysCache.set(peerAid, {
|
|
2548
|
+
items: normalized.map((item) => ({ ...item })),
|
|
2549
|
+
expireAt: Date.now() / 1000 + 300,
|
|
2550
|
+
});
|
|
2551
|
+
this._e2ee.cachePrekey(peerAid, normalized[0]);
|
|
2552
|
+
return normalized.map((item) => ({ ...item }));
|
|
2553
|
+
}
|
|
2461
2554
|
}
|
|
2462
2555
|
if (result.found) {
|
|
2463
2556
|
throw new ValidationError(`invalid prekey response for ${peerAid}`);
|
|
@@ -2475,7 +2568,10 @@ export class AUNClient {
|
|
|
2475
2568
|
async _fetchPeerPrekey(peerAid) {
|
|
2476
2569
|
const cachedList = this._peerPrekeysCache.get(peerAid);
|
|
2477
2570
|
if (cachedList && Date.now() / 1000 < cachedList.expireAt && cachedList.items.length > 0) {
|
|
2478
|
-
|
|
2571
|
+
const normalized = normalizePeerPrekeys(cachedList.items);
|
|
2572
|
+
if (normalized.length > 0) {
|
|
2573
|
+
return { ...normalized[0] };
|
|
2574
|
+
}
|
|
2479
2575
|
}
|
|
2480
2576
|
const prekeys = await this._fetchPeerPrekeys(peerAid);
|
|
2481
2577
|
if (prekeys.length === 0) {
|
|
@@ -2852,14 +2948,16 @@ export class AUNClient {
|
|
|
2852
2948
|
this._enqueuePendingDecrypt(groupId, message);
|
|
2853
2949
|
continue;
|
|
2854
2950
|
}
|
|
2855
|
-
|
|
2951
|
+
const thought = {
|
|
2856
2952
|
thought_id: thoughtId,
|
|
2857
2953
|
message_id: thoughtId,
|
|
2858
|
-
reply_to: item.reply_to,
|
|
2859
2954
|
payload: decrypted.payload,
|
|
2860
2955
|
created_at: item.created_at,
|
|
2861
2956
|
e2ee: decrypted.e2ee,
|
|
2862
|
-
}
|
|
2957
|
+
};
|
|
2958
|
+
if ('context' in item)
|
|
2959
|
+
thought.context = item.context;
|
|
2960
|
+
thoughts.push(thought);
|
|
2863
2961
|
}
|
|
2864
2962
|
return { ...result, thoughts };
|
|
2865
2963
|
}
|
|
@@ -2902,16 +3000,18 @@ export class AUNClient {
|
|
|
2902
3000
|
continue;
|
|
2903
3001
|
}
|
|
2904
3002
|
}
|
|
2905
|
-
|
|
3003
|
+
const thought = {
|
|
2906
3004
|
thought_id: thoughtId,
|
|
2907
3005
|
message_id: thoughtId,
|
|
2908
|
-
reply_to: item.reply_to,
|
|
2909
3006
|
from: fromAid,
|
|
2910
3007
|
to: toAid,
|
|
2911
3008
|
payload: decrypted.payload,
|
|
2912
3009
|
created_at: item.created_at,
|
|
2913
3010
|
e2ee: decrypted.e2ee,
|
|
2914
|
-
}
|
|
3011
|
+
};
|
|
3012
|
+
if ('context' in item)
|
|
3013
|
+
thought.context = item.context;
|
|
3014
|
+
thoughts.push(thought);
|
|
2915
3015
|
}
|
|
2916
3016
|
return { ...result, thoughts };
|
|
2917
3017
|
}
|
|
@@ -3997,10 +4097,12 @@ export class AUNClient {
|
|
|
3997
4097
|
}
|
|
3998
4098
|
if (method === 'group.thought.put' || method === 'group.thought.get'
|
|
3999
4099
|
|| method === 'message.thought.put' || method === 'message.thought.get') {
|
|
4000
|
-
const
|
|
4001
|
-
const
|
|
4002
|
-
|
|
4003
|
-
|
|
4100
|
+
const context = isJsonObject(params.context) ? params.context : null;
|
|
4101
|
+
const contextType = String(context?.type ?? '').trim();
|
|
4102
|
+
const contextId = String(context?.id ?? '').trim();
|
|
4103
|
+
const hasContext = contextType.length > 0 && contextId.length > 0;
|
|
4104
|
+
if (!hasContext) {
|
|
4105
|
+
throw new ValidationError(`${method} requires context.type + context.id`);
|
|
4004
4106
|
}
|
|
4005
4107
|
}
|
|
4006
4108
|
if (method === 'group.thought.get' && !String(params.sender_aid ?? '').trim()) {
|