@agentunion/fastaun-browser 0.5.1 → 0.5.3
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 +570 -504
- package/_packed_docs/CHANGELOG-validators.md +134 -131
- package/_packed_docs/CHANGELOG.md +570 -504
- package/_packed_docs/INDEX.md +65 -52
- package/_packed_docs/KITE_DOCS_GUIDE.md +23 -18
- package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +169 -116
- package/_packed_docs/aun-perf-audit-critical-bugs.md +315 -0
- package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +263 -261
- package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +328 -328
- package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +2 -2
- package/_packed_docs/protocol/00A-/350/256/276/350/256/241/345/216/237/345/210/231-/344/270/272Agent/350/200/214/347/224/237.md +1 -1
- package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +39 -16
- package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +8 -5
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +18 -19
- package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +1 -1
- package/_packed_docs/protocol/08-AUN-E2EE-Group.md +293 -294
- package/_packed_docs/protocol/08-AUN-E2EE.md +12 -10
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +183 -60
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +4 -4
- package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +1 -1
- package/_packed_docs/protocol/16-/347/263/273/347/273/237/347/233/256/345/275/225/344/277/235/346/212/244/346/226/271/346/241/210.md +177 -177
- package/_packed_docs/protocol/README.md +7 -6
- package/_packed_docs/protocol/aun-docs-guide.md +5 -4
- package/_packed_docs/protocol/index.md +9 -8
- package/_packed_docs/protocol//350/215/211/346/241/210-/346/213/222/347/273/235/344/277/241/345/217/267/345/215/217/350/256/256.md +1 -1
- package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +13 -13
- package/_packed_docs/protocol//351/231/204/345/275/225L-E2EE/345/256/236/347/216/260/346/214/207/345/215/227.md +9 -9
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +15 -13
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +20 -1
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +26 -18
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +33 -34
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +274 -4
- package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +41 -13
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +28 -12
- package/_packed_docs/sdk/09-group-rpc-manual.md +237 -142
- package/_packed_docs/sdk/09-message-rpc-manual.md +50 -28
- package/_packed_docs/sdk/09-payload-reference.md +3 -3
- package/_packed_docs/sdk/09-storage-rpc-manual.md +1 -1
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +12 -9
- package/_packed_docs/sdk/E2EE_V2/346/266/210/346/201/257/351/200/232/344/277/241/346/227/266/345/272/217/345/233/276.md +3 -2
- package/_packed_docs/sdk/INDEX.md +29 -28
- package/_packed_docs/sdk/Notify/351/200/232/347/237/245/346/226/271/346/241/210.md +6 -2
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +18 -9
- package/dist/agent-md.js.map +1 -1
- package/dist/bundle.js +1084 -272
- package/dist/client/delivery.d.ts +4 -0
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +174 -7
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +79 -8
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +27 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +118 -12
- package/dist/client.js.map +1 -1
- package/dist/facades.d.ts +6 -0
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +213 -33
- package/dist/facades.js.map +1 -1
- package/dist/group-index.d.ts +105 -0
- package/dist/group-index.d.ts.map +1 -0
- package/dist/group-index.js +252 -0
- package/dist/group-index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +15 -0
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts +7 -1
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +63 -2
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +3 -1
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +22 -1
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/tools/cross-sdk-agent.js +3 -1
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +2 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +17 -31
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -460,7 +460,7 @@ var init_indexeddb_store = __esm({
|
|
|
460
460
|
});
|
|
461
461
|
|
|
462
462
|
// src/version.ts
|
|
463
|
-
var VERSION = "0.5.
|
|
463
|
+
var VERSION = "0.5.3";
|
|
464
464
|
|
|
465
465
|
// src/types.ts
|
|
466
466
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
@@ -1918,10 +1918,11 @@ var STORE_METADATA = "metadata";
|
|
|
1918
1918
|
var STORE_INSTANCE_STATE = "instance_state";
|
|
1919
1919
|
var STORE_GROUP_STATE = "group_state";
|
|
1920
1920
|
var STORE_AGENT_MD_CACHE = "agent_md_cache";
|
|
1921
|
+
var STORE_GROUP_INDEX_CACHE = "group_index_cache";
|
|
1921
1922
|
var STORE_PENDING_IDENTITIES = "pending_identities";
|
|
1922
1923
|
var STORE_PENDING_BINDS = "pending_binds";
|
|
1923
1924
|
var DB_NAME = "aun-keystore";
|
|
1924
|
-
var DB_VERSION =
|
|
1925
|
+
var DB_VERSION = 9;
|
|
1925
1926
|
function safeAid(aid) {
|
|
1926
1927
|
return aid.replace(/[/\\:]/g, "_");
|
|
1927
1928
|
}
|
|
@@ -1986,6 +1987,12 @@ function agentMdCachePrefix(ownerAid) {
|
|
|
1986
1987
|
function agentMdCacheStoreKey(ownerAid, targetAid) {
|
|
1987
1988
|
return `${agentMdCachePrefix(ownerAid)}${encodePart(targetAid)}`;
|
|
1988
1989
|
}
|
|
1990
|
+
function groupIndexCachePrefix(localAid) {
|
|
1991
|
+
return `${safeAid(localAid)}|`;
|
|
1992
|
+
}
|
|
1993
|
+
function groupIndexCacheStoreKey(localAid, groupAid) {
|
|
1994
|
+
return `${groupIndexCachePrefix(localAid)}${encodePart(groupAid)}`;
|
|
1995
|
+
}
|
|
1989
1996
|
function pendingIdentityPrefix(aid) {
|
|
1990
1997
|
return `${safeAid(aid)}-`;
|
|
1991
1998
|
}
|
|
@@ -2039,6 +2046,59 @@ function mergeAgentMdCacheRecord(aid, current, fields) {
|
|
|
2039
2046
|
out.updated_at = Date.now();
|
|
2040
2047
|
return out;
|
|
2041
2048
|
}
|
|
2049
|
+
function defaultGroupIndexCacheRecord(localAid, groupAid) {
|
|
2050
|
+
return {
|
|
2051
|
+
local_aid: localAid,
|
|
2052
|
+
group_aid: groupAid,
|
|
2053
|
+
index_jsonl: "",
|
|
2054
|
+
remote_meta: {},
|
|
2055
|
+
local_etag: "",
|
|
2056
|
+
settings: {},
|
|
2057
|
+
entry_etags: {},
|
|
2058
|
+
updated_at: 0
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
function normalizeGroupIndexCacheRecord(localAid, groupAid, value) {
|
|
2062
|
+
if (!isRecord(value)) return null;
|
|
2063
|
+
const out = defaultGroupIndexCacheRecord(localAid, groupAid);
|
|
2064
|
+
out.local_aid = String(value.local_aid ?? localAid).trim() || localAid;
|
|
2065
|
+
out.group_aid = String(value.group_aid ?? groupAid).trim() || groupAid;
|
|
2066
|
+
out.index_jsonl = String(value.index_jsonl ?? "");
|
|
2067
|
+
out.local_etag = String(value.local_etag ?? "");
|
|
2068
|
+
out.remote_meta = isRecord(value.remote_meta) ? deepClone(value.remote_meta) : {};
|
|
2069
|
+
out.settings = isRecord(value.settings) ? deepClone(value.settings) : {};
|
|
2070
|
+
if (isRecord(value.entry_etags)) {
|
|
2071
|
+
out.entry_etags = Object.fromEntries(Object.entries(value.entry_etags).map(([key, etag]) => [key, String(etag ?? "")]));
|
|
2072
|
+
}
|
|
2073
|
+
const updatedAt = Number(value.updated_at ?? 0);
|
|
2074
|
+
out.updated_at = Number.isFinite(updatedAt) ? Math.trunc(updatedAt) : 0;
|
|
2075
|
+
return out;
|
|
2076
|
+
}
|
|
2077
|
+
function mergeGroupIndexCacheRecord(localAid, groupAid, current, fields) {
|
|
2078
|
+
const out = current ? deepClone(current) : defaultGroupIndexCacheRecord(localAid, groupAid);
|
|
2079
|
+
out.local_aid = localAid;
|
|
2080
|
+
out.group_aid = groupAid;
|
|
2081
|
+
if (Object.prototype.hasOwnProperty.call(fields, "index_jsonl") && fields.index_jsonl !== void 0 && fields.index_jsonl !== null) {
|
|
2082
|
+
out.index_jsonl = String(fields.index_jsonl ?? "");
|
|
2083
|
+
}
|
|
2084
|
+
if (Object.prototype.hasOwnProperty.call(fields, "local_etag") && fields.local_etag !== void 0 && fields.local_etag !== null) {
|
|
2085
|
+
out.local_etag = String(fields.local_etag ?? "");
|
|
2086
|
+
}
|
|
2087
|
+
if (isRecord(fields.remote_meta)) {
|
|
2088
|
+
out.remote_meta = { ...out.remote_meta, ...deepClone(fields.remote_meta) };
|
|
2089
|
+
}
|
|
2090
|
+
if (isRecord(fields.settings)) {
|
|
2091
|
+
out.settings = { ...out.settings, ...deepClone(fields.settings) };
|
|
2092
|
+
}
|
|
2093
|
+
if (isRecord(fields.entry_etags)) {
|
|
2094
|
+
out.entry_etags = {
|
|
2095
|
+
...out.entry_etags,
|
|
2096
|
+
...Object.fromEntries(Object.entries(fields.entry_etags).map(([key, etag]) => [key, String(etag ?? "")]))
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
out.updated_at = Date.now();
|
|
2100
|
+
return out;
|
|
2101
|
+
}
|
|
2042
2102
|
var _ENC_ALGO = "AES-GCM";
|
|
2043
2103
|
var _PBKDF2_ITERATIONS = 1e5;
|
|
2044
2104
|
function _uint8ToBase64(bytes) {
|
|
@@ -2098,6 +2158,7 @@ function openDB() {
|
|
|
2098
2158
|
STORE_INSTANCE_STATE,
|
|
2099
2159
|
STORE_GROUP_STATE,
|
|
2100
2160
|
STORE_AGENT_MD_CACHE,
|
|
2161
|
+
STORE_GROUP_INDEX_CACHE,
|
|
2101
2162
|
STORE_PENDING_IDENTITIES,
|
|
2102
2163
|
STORE_PENDING_BINDS
|
|
2103
2164
|
]) {
|
|
@@ -2987,6 +3048,26 @@ var _IndexedDBTokenStore = class _IndexedDBTokenStore {
|
|
|
2987
3048
|
}
|
|
2988
3049
|
return [...aids].sort();
|
|
2989
3050
|
}
|
|
3051
|
+
// ── group.index Cache ───────────────────────────────────
|
|
3052
|
+
async loadGroupIndexCache(localAid, groupAid) {
|
|
3053
|
+
const local = String(localAid ?? "").trim();
|
|
3054
|
+
const group = String(groupAid ?? "").trim();
|
|
3055
|
+
if (!local || !group) return null;
|
|
3056
|
+
const data = await idbGet(STORE_GROUP_INDEX_CACHE, groupIndexCacheStoreKey(local, group));
|
|
3057
|
+
const record = normalizeGroupIndexCacheRecord(local, group, data);
|
|
3058
|
+
return record ? deepClone(record) : null;
|
|
3059
|
+
}
|
|
3060
|
+
async upsertGroupIndexCache(localAid, groupAid, fields) {
|
|
3061
|
+
const local = String(localAid ?? "").trim();
|
|
3062
|
+
const group = String(groupAid ?? "").trim();
|
|
3063
|
+
if (!local || !group) {
|
|
3064
|
+
throw new Error("upsertGroupIndexCache requires localAid and groupAid");
|
|
3065
|
+
}
|
|
3066
|
+
const current = await this.loadGroupIndexCache(local, group);
|
|
3067
|
+
const record = mergeGroupIndexCacheRecord(local, group, current, fields ?? {});
|
|
3068
|
+
await idbPut(STORE_GROUP_INDEX_CACHE, groupIndexCacheStoreKey(local, group), record);
|
|
3069
|
+
return deepClone(record);
|
|
3070
|
+
}
|
|
2990
3071
|
// ── Group State(群组状态快照) ─────────────────────────────
|
|
2991
3072
|
async saveGroupState(groupId, state) {
|
|
2992
3073
|
const key = encodePart(groupId);
|
|
@@ -3355,7 +3436,7 @@ var AgentMdManager = class _AgentMdManager {
|
|
|
3355
3436
|
}
|
|
3356
3437
|
const etags = meta.agent_md_etags;
|
|
3357
3438
|
if (!isJsonObject(etags)) return;
|
|
3358
|
-
for (const key of ["requester", "peer", "receiver", "target", "to", "sender", "from"]) {
|
|
3439
|
+
for (const key of ["requester", "peer", "group", "receiver", "target", "to", "sender", "from"]) {
|
|
3359
3440
|
const item = etags[key];
|
|
3360
3441
|
if (!isJsonObject(item)) continue;
|
|
3361
3442
|
await this.observeMeta(
|
|
@@ -3370,19 +3451,34 @@ var AgentMdManager = class _AgentMdManager {
|
|
|
3370
3451
|
if (!isJsonObject(envelope)) return;
|
|
3371
3452
|
if (!isJsonObject(envelope.agent_md)) return;
|
|
3372
3453
|
const agentMd = envelope.agent_md;
|
|
3373
|
-
if (
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3454
|
+
if (isJsonObject(agentMd.sender)) {
|
|
3455
|
+
const sender = agentMd.sender;
|
|
3456
|
+
let senderAid = String(sender.aid ?? "").trim();
|
|
3457
|
+
if (!senderAid) {
|
|
3458
|
+
const aad = isJsonObject(envelope.aad) ? envelope.aad : {};
|
|
3459
|
+
senderAid = String(aad.from ?? envelope.from ?? "").trim();
|
|
3460
|
+
}
|
|
3461
|
+
await this.observeMeta(
|
|
3462
|
+
senderAid,
|
|
3463
|
+
String(sender.etag ?? "").trim(),
|
|
3464
|
+
String(sender.last_modified ?? sender.lastModified ?? "").trim(),
|
|
3465
|
+
"envelope.sender"
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3468
|
+
if (isJsonObject(agentMd.group)) {
|
|
3469
|
+
const group = agentMd.group;
|
|
3470
|
+
let groupAid = String(group.aid ?? "").trim();
|
|
3471
|
+
if (!groupAid) {
|
|
3472
|
+
const aad = isJsonObject(envelope.aad) ? envelope.aad : {};
|
|
3473
|
+
groupAid = String(envelope.group_aid ?? envelope.group_id ?? aad.group_aid ?? aad.group_id ?? "").trim();
|
|
3474
|
+
}
|
|
3475
|
+
await this.observeMeta(
|
|
3476
|
+
groupAid,
|
|
3477
|
+
String(group.etag ?? "").trim(),
|
|
3478
|
+
String(group.last_modified ?? group.lastModified ?? "").trim(),
|
|
3479
|
+
"envelope.group"
|
|
3480
|
+
);
|
|
3481
|
+
}
|
|
3386
3482
|
}
|
|
3387
3483
|
eventSnapshot() {
|
|
3388
3484
|
if (!this._localAgentMdEtag && !this._remoteAgentMdEtag) return null;
|
|
@@ -6278,6 +6374,16 @@ var RPCTransport = class {
|
|
|
6278
6374
|
setMetaObserver(observer) {
|
|
6279
6375
|
this._metaObserver = observer;
|
|
6280
6376
|
}
|
|
6377
|
+
async _notifyMetaObserver(message) {
|
|
6378
|
+
if (this._metaObserver === null) return;
|
|
6379
|
+
const meta = message._meta;
|
|
6380
|
+
if (!isJsonObject(meta)) return;
|
|
6381
|
+
try {
|
|
6382
|
+
await this._metaObserver(meta);
|
|
6383
|
+
} catch (exc) {
|
|
6384
|
+
this._log.debug(`meta_observer raised: ${String(exc)}`);
|
|
6385
|
+
}
|
|
6386
|
+
}
|
|
6281
6387
|
/** 设置 trace 模式:off / log / diag */
|
|
6282
6388
|
setTraceMode(mode) {
|
|
6283
6389
|
if (mode !== "off" && mode !== "log" && mode !== "diag") {
|
|
@@ -6472,7 +6578,7 @@ var RPCTransport = class {
|
|
|
6472
6578
|
this._drainRpcQueue();
|
|
6473
6579
|
}, effectiveTimeout);
|
|
6474
6580
|
const pending = {
|
|
6475
|
-
resolve: (response) => {
|
|
6581
|
+
resolve: async (response) => {
|
|
6476
6582
|
clearTimeout(timer);
|
|
6477
6583
|
const elapsed = Date.now() - tStart;
|
|
6478
6584
|
if (response.error !== void 0) {
|
|
@@ -6490,16 +6596,7 @@ var RPCTransport = class {
|
|
|
6490
6596
|
if (traceId) {
|
|
6491
6597
|
this._log.info(`[trace=${traceId}] rpc_recv method=${method} rpc_id=${rpcId} duration_ms=${elapsed} status=ok`);
|
|
6492
6598
|
}
|
|
6493
|
-
|
|
6494
|
-
const meta = response._meta;
|
|
6495
|
-
if (isJsonObject(meta)) {
|
|
6496
|
-
try {
|
|
6497
|
-
this._metaObserver(meta);
|
|
6498
|
-
} catch (exc) {
|
|
6499
|
-
this._log.debug(`meta_observer raised: ${String(exc)}`);
|
|
6500
|
-
}
|
|
6501
|
-
}
|
|
6502
|
-
}
|
|
6599
|
+
await this._notifyMetaObserver(response);
|
|
6503
6600
|
const respTrace = response._trace;
|
|
6504
6601
|
if (respTrace && typeof respTrace === "object" && !Array.isArray(respTrace)) {
|
|
6505
6602
|
this._handleResponseTrace(method, "ok", elapsed, respTrace);
|
|
@@ -6781,14 +6878,7 @@ var RPCTransport = class {
|
|
|
6781
6878
|
const protocolEvent = method.slice(6);
|
|
6782
6879
|
const sdkEvent = EVENT_NAME_MAP[protocolEvent] ?? protocolEvent;
|
|
6783
6880
|
this._log.debug(`event recv: event=${sdkEvent} ${summarizeDict(message.params, DIAG_RESULT_FIELDS)}`);
|
|
6784
|
-
|
|
6785
|
-
if (this._metaObserver !== null && isJsonObject(meta2)) {
|
|
6786
|
-
try {
|
|
6787
|
-
this._metaObserver(meta2);
|
|
6788
|
-
} catch (exc) {
|
|
6789
|
-
this._log.debug(`event meta_observer raised: ${String(exc)}`);
|
|
6790
|
-
}
|
|
6791
|
-
}
|
|
6881
|
+
void this._notifyMetaObserver(message);
|
|
6792
6882
|
const params2 = message.params ?? {};
|
|
6793
6883
|
if ("_trace" in params2) {
|
|
6794
6884
|
const eventTrace = params2._trace;
|
|
@@ -6811,14 +6901,7 @@ var RPCTransport = class {
|
|
|
6811
6901
|
this._dispatcher.publish(`_raw.${sdkEvent}`, params2);
|
|
6812
6902
|
return;
|
|
6813
6903
|
}
|
|
6814
|
-
|
|
6815
|
-
if (this._metaObserver !== null && isJsonObject(meta)) {
|
|
6816
|
-
try {
|
|
6817
|
-
this._metaObserver(meta);
|
|
6818
|
-
} catch (exc) {
|
|
6819
|
-
this._log.debug(`notification meta_observer raised: ${String(exc)}`);
|
|
6820
|
-
}
|
|
6821
|
-
}
|
|
6904
|
+
void this._notifyMetaObserver(message);
|
|
6822
6905
|
this._log.debug(`notification recv: method=${method || "<no-method>"}`);
|
|
6823
6906
|
this._dispatcher.publish("notification", message);
|
|
6824
6907
|
}
|
|
@@ -7362,6 +7445,7 @@ var ClientRuntime = class {
|
|
|
7362
7445
|
// src/client/delivery.ts
|
|
7363
7446
|
var PUSHED_SEQS_LIMIT = 5e4;
|
|
7364
7447
|
var PENDING_ORDERED_LIMIT = 5e4;
|
|
7448
|
+
var MESSAGE_RECALL_SEEN_LIMIT = 1e4;
|
|
7365
7449
|
var GROUP_RECALL_SEEN_LIMIT = 1e4;
|
|
7366
7450
|
var SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS = 200;
|
|
7367
7451
|
var P2P_GAP_FILL_RETRY_LIMIT = 12;
|
|
@@ -7387,6 +7471,22 @@ var APP_MESSAGE_ENVELOPE_KEYS = [
|
|
|
7387
7471
|
"headers",
|
|
7388
7472
|
"payload_type"
|
|
7389
7473
|
];
|
|
7474
|
+
var RECALL_PAYLOAD_KEYS = [
|
|
7475
|
+
"message_ids",
|
|
7476
|
+
"target_message_seqs",
|
|
7477
|
+
"recalled_message_id",
|
|
7478
|
+
"target_message_id",
|
|
7479
|
+
"original_message_id",
|
|
7480
|
+
"target_seq",
|
|
7481
|
+
"original_seq",
|
|
7482
|
+
"notice_message_id",
|
|
7483
|
+
"notice_seq",
|
|
7484
|
+
"event_seq",
|
|
7485
|
+
"sender_aid",
|
|
7486
|
+
"recalled_by",
|
|
7487
|
+
"recalled_at",
|
|
7488
|
+
"reason"
|
|
7489
|
+
];
|
|
7390
7490
|
var APP_SEND_ENVELOPE_METHODS = /* @__PURE__ */ new Set([
|
|
7391
7491
|
"message.send",
|
|
7392
7492
|
"group.send",
|
|
@@ -7509,6 +7609,10 @@ var MessageDeliveryEngine = class {
|
|
|
7509
7609
|
await this.publishOrderedGroupChanged(payload);
|
|
7510
7610
|
return;
|
|
7511
7611
|
}
|
|
7612
|
+
if (event === "message.recalled") {
|
|
7613
|
+
await this.publishMessageRecallTombstone(seq, payload);
|
|
7614
|
+
return;
|
|
7615
|
+
}
|
|
7512
7616
|
await client._publishAppEvent(event, payload);
|
|
7513
7617
|
}
|
|
7514
7618
|
async publishOrderedGroupChanged(payload) {
|
|
@@ -7689,6 +7793,11 @@ var MessageDeliveryEngine = class {
|
|
|
7689
7793
|
event[key] = msg[key];
|
|
7690
7794
|
}
|
|
7691
7795
|
}
|
|
7796
|
+
for (const key of RECALL_PAYLOAD_KEYS) {
|
|
7797
|
+
if (Object.prototype.hasOwnProperty.call(msg, key) && !(key in event)) {
|
|
7798
|
+
event[key] = msg[key];
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7692
7801
|
const rawIds = event.message_ids;
|
|
7693
7802
|
let messageIds = Array.isArray(rawIds) ? rawIds.map((item) => String(item ?? "").trim()).filter(Boolean) : [];
|
|
7694
7803
|
if (messageIds.length === 0) {
|
|
@@ -7720,6 +7829,48 @@ var MessageDeliveryEngine = class {
|
|
|
7720
7829
|
if (recall) return { event: "message.recalled", payload: recall };
|
|
7721
7830
|
return { event: "message.received", payload: message };
|
|
7722
7831
|
}
|
|
7832
|
+
messageRecallDedupKey(payload) {
|
|
7833
|
+
const ids = payload.message_ids;
|
|
7834
|
+
const idPart = Array.isArray(ids) ? ids.map((i) => String(i ?? "").trim()).filter(Boolean).sort().join(",") : String(ids ?? "").trim();
|
|
7835
|
+
if (idPart) return `p2p|id:${idPart}`;
|
|
7836
|
+
for (const key of ["recalled_message_id", "target_message_id", "original_message_id"]) {
|
|
7837
|
+
const value = String(payload[key] ?? "").trim();
|
|
7838
|
+
if (value) return `p2p|id:${value}`;
|
|
7839
|
+
}
|
|
7840
|
+
const rawSeqs = payload.target_message_seqs;
|
|
7841
|
+
const seqPart = Array.isArray(rawSeqs) ? rawSeqs.map((seq) => String(seq ?? "").trim()).filter(Boolean).sort().join(",") : String(rawSeqs ?? payload.target_seq ?? payload.original_seq ?? "").trim();
|
|
7842
|
+
if (seqPart) {
|
|
7843
|
+
const fromAid = String(payload.from ?? payload.from_aid ?? payload.sender_aid ?? "").trim();
|
|
7844
|
+
const toAid = String(payload.to ?? payload.to_aid ?? "").trim();
|
|
7845
|
+
return `p2p|from:${fromAid}|to:${toAid}|seq:${seqPart}`;
|
|
7846
|
+
}
|
|
7847
|
+
const tombstoneId = String(payload.tombstone_message_id ?? payload.message_id ?? "").trim();
|
|
7848
|
+
if (tombstoneId) return `p2p|tombstone:${tombstoneId}`;
|
|
7849
|
+
return `p2p|unknown:${Date.now()}:${Math.random()}`;
|
|
7850
|
+
}
|
|
7851
|
+
async publishMessageRecallTombstone(seq, message) {
|
|
7852
|
+
const client = this.runtime.client;
|
|
7853
|
+
const eventPayload = this.recallEventFromMessage(message);
|
|
7854
|
+
if (!eventPayload) return false;
|
|
7855
|
+
const dedupKey = this.messageRecallDedupKey(eventPayload);
|
|
7856
|
+
let seen = client._messageRecallSeen;
|
|
7857
|
+
if (!seen) {
|
|
7858
|
+
seen = /* @__PURE__ */ new Map();
|
|
7859
|
+
client._messageRecallSeen = seen;
|
|
7860
|
+
}
|
|
7861
|
+
if (seen.has(dedupKey)) {
|
|
7862
|
+
client._clientLog.debug(`message.recalled dedup suppressed: seq=${String(seq)} key=${dedupKey}`);
|
|
7863
|
+
return false;
|
|
7864
|
+
}
|
|
7865
|
+
seen.set(dedupKey, Date.now());
|
|
7866
|
+
if (seen.size > MESSAGE_RECALL_SEEN_LIMIT) {
|
|
7867
|
+
const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - MESSAGE_RECALL_SEEN_LIMIT);
|
|
7868
|
+
for (const [oldKey] of drop) seen.delete(oldKey);
|
|
7869
|
+
}
|
|
7870
|
+
await client._publishAppEvent("message.recalled", eventPayload);
|
|
7871
|
+
client._clientLog.debug(`message.recalled published: seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
7872
|
+
return true;
|
|
7873
|
+
}
|
|
7723
7874
|
recallEventFromGroupMessage(message) {
|
|
7724
7875
|
if (!isJsonObject(message)) return null;
|
|
7725
7876
|
const msg = message;
|
|
@@ -7734,6 +7885,11 @@ var MessageDeliveryEngine = class {
|
|
|
7734
7885
|
event[key] = msg[key];
|
|
7735
7886
|
}
|
|
7736
7887
|
}
|
|
7888
|
+
for (const key of RECALL_PAYLOAD_KEYS) {
|
|
7889
|
+
if (Object.prototype.hasOwnProperty.call(msg, key) && !(key in event)) {
|
|
7890
|
+
event[key] = msg[key];
|
|
7891
|
+
}
|
|
7892
|
+
}
|
|
7737
7893
|
const rawIds = event.message_ids;
|
|
7738
7894
|
let messageIds = Array.isArray(rawIds) ? rawIds.map((item) => String(item ?? "").trim()).filter(Boolean) : [];
|
|
7739
7895
|
if (messageIds.length === 0) {
|
|
@@ -7758,15 +7914,29 @@ var MessageDeliveryEngine = class {
|
|
|
7758
7914
|
return event;
|
|
7759
7915
|
}
|
|
7760
7916
|
groupRecallDedupKey(groupId, payload) {
|
|
7917
|
+
const normalizedGroupId2 = normalizeGroupId(groupId) || String(groupId ?? "").trim();
|
|
7761
7918
|
const ids = payload.message_ids;
|
|
7762
|
-
const idPart = Array.isArray(ids) ? ids.map((i) => String(i ?? "").trim()).filter(Boolean).sort().join(",") : String(ids ?? "");
|
|
7763
|
-
return `${
|
|
7919
|
+
const idPart = Array.isArray(ids) ? ids.map((i) => String(i ?? "").trim()).filter(Boolean).sort().join(",") : String(ids ?? "").trim();
|
|
7920
|
+
if (idPart) return `${normalizedGroupId2}|id:${idPart}`;
|
|
7921
|
+
for (const key of ["recalled_message_id", "target_message_id", "original_message_id"]) {
|
|
7922
|
+
const value = String(payload[key] ?? "").trim();
|
|
7923
|
+
if (value) return `${normalizedGroupId2}|id:${value}`;
|
|
7924
|
+
}
|
|
7925
|
+
const rawSeqs = payload.target_message_seqs;
|
|
7926
|
+
const seqPart = Array.isArray(rawSeqs) ? rawSeqs.map((seq) => String(seq ?? "").trim()).filter(Boolean).sort().join(",") : String(rawSeqs ?? payload.original_seq ?? "").trim();
|
|
7927
|
+
if (seqPart) return `${normalizedGroupId2}|seq:${seqPart}`;
|
|
7928
|
+
const tombstoneId = String(payload.tombstone_message_id ?? payload.message_id ?? "").trim();
|
|
7929
|
+
if (tombstoneId) return `${normalizedGroupId2}|tombstone:${tombstoneId}`;
|
|
7930
|
+
return `${normalizedGroupId2}|unknown:${Date.now()}:${Math.random()}`;
|
|
7764
7931
|
}
|
|
7765
7932
|
async publishGroupRecallTombstone(groupId, seq, message) {
|
|
7766
7933
|
const client = this.runtime.client;
|
|
7767
7934
|
const eventPayload = this.recallEventFromGroupMessage(message);
|
|
7768
7935
|
if (!eventPayload) return false;
|
|
7769
|
-
const
|
|
7936
|
+
const rawGroupId = String(eventPayload.group_id ?? groupId ?? "").trim();
|
|
7937
|
+
const dedupGroupId = normalizeGroupId(rawGroupId) || rawGroupId;
|
|
7938
|
+
if (dedupGroupId) eventPayload.group_id = dedupGroupId;
|
|
7939
|
+
const dedupKey = this.groupRecallDedupKey(dedupGroupId, eventPayload);
|
|
7770
7940
|
let seen = client._groupRecallSeen;
|
|
7771
7941
|
if (!seen) {
|
|
7772
7942
|
seen = /* @__PURE__ */ new Map();
|
|
@@ -7883,12 +8053,68 @@ var MessageDeliveryEngine = class {
|
|
|
7883
8053
|
}
|
|
7884
8054
|
return true;
|
|
7885
8055
|
}
|
|
8056
|
+
async runPushProcessSerialized(ns, operation) {
|
|
8057
|
+
const client = this.runtime.client;
|
|
8058
|
+
if (!ns) {
|
|
8059
|
+
await operation();
|
|
8060
|
+
return;
|
|
8061
|
+
}
|
|
8062
|
+
let queues = client._pushProcessQueues;
|
|
8063
|
+
if (!queues) {
|
|
8064
|
+
queues = /* @__PURE__ */ new Map();
|
|
8065
|
+
client._pushProcessQueues = queues;
|
|
8066
|
+
}
|
|
8067
|
+
const previous = queues.get(ns) ?? Promise.resolve();
|
|
8068
|
+
const current = previous.catch(() => void 0).then(operation);
|
|
8069
|
+
const stored = current.then(() => void 0, () => void 0);
|
|
8070
|
+
queues.set(ns, stored);
|
|
8071
|
+
try {
|
|
8072
|
+
await current;
|
|
8073
|
+
} finally {
|
|
8074
|
+
if (queues.get(ns) === stored) queues.delete(ns);
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
7886
8077
|
onRawMessageReceived(data) {
|
|
7887
8078
|
const client = this.runtime.client;
|
|
7888
8079
|
client._clientLog.debug(`_onRawMessageReceived enter: from=${data?.from ?? "-"} mid=${data?.message_id ?? "-"} seq=${data?.seq ?? "-"}`);
|
|
7889
|
-
client.
|
|
8080
|
+
const ns = isJsonObject(data) && client._aid && data.seq !== void 0 ? `p2p:${client._aid}` : "";
|
|
8081
|
+
client._safeAsync(this.runPushProcessSerialized(ns, () => this.processAndPublishMessage(data)));
|
|
7890
8082
|
client._clientLog.debug("_onRawMessageReceived exit: elapsed=0ms (dispatched async)");
|
|
7891
8083
|
}
|
|
8084
|
+
async onRawMessageRecalled(data) {
|
|
8085
|
+
const client = this.runtime.client;
|
|
8086
|
+
if (!isJsonObject(data)) return;
|
|
8087
|
+
const msg = { ...data };
|
|
8088
|
+
if (!("type" in msg)) msg.type = "message.recalled";
|
|
8089
|
+
if (!this.messageTargetsCurrentInstance(msg)) return;
|
|
8090
|
+
const seq = msg.seq;
|
|
8091
|
+
if (seq !== void 0 && seq !== null && client._aid) {
|
|
8092
|
+
const ns = `p2p:${client._aid}`;
|
|
8093
|
+
if (seq > 0) client._seqTracker.updateMaxSeen(ns, seq);
|
|
8094
|
+
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
8095
|
+
const seqNeedsPull = client._seqTracker.onMessageSeq(ns, seq);
|
|
8096
|
+
const published = await this.publishOrderedMessage("message.recalled", ns, seq, msg);
|
|
8097
|
+
const contigAfter = client._seqTracker.getContiguousSeq(ns);
|
|
8098
|
+
if (seqNeedsPull && !published) {
|
|
8099
|
+
client._safeAsync(this.fillP2pGap());
|
|
8100
|
+
}
|
|
8101
|
+
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
8102
|
+
if (contig > 0) {
|
|
8103
|
+
const ackSeq = this.clampAckSeq("message.ack", "seq", ns, contig);
|
|
8104
|
+
client._transport.call("message.ack", {
|
|
8105
|
+
seq: ackSeq,
|
|
8106
|
+
device_id: client._deviceId,
|
|
8107
|
+
slot_id: client._slotId,
|
|
8108
|
+
_rpc_background: true
|
|
8109
|
+
}).catch((e) => {
|
|
8110
|
+
client._clientLog.warn(`P2P recall auto-ack failed:${String(e)}`);
|
|
8111
|
+
});
|
|
8112
|
+
}
|
|
8113
|
+
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
8114
|
+
return;
|
|
8115
|
+
}
|
|
8116
|
+
await this.publishMessageRecallTombstone(seq, msg);
|
|
8117
|
+
}
|
|
7892
8118
|
async processAndPublishMessage(data) {
|
|
7893
8119
|
const client = this.runtime.client;
|
|
7894
8120
|
try {
|
|
@@ -7954,7 +8180,8 @@ var MessageDeliveryEngine = class {
|
|
|
7954
8180
|
onRawGroupMessageCreated(data) {
|
|
7955
8181
|
const client = this.runtime.client;
|
|
7956
8182
|
client._clientLog.debug(`_onRawGroupMessageCreated enter: group_id=${data?.group_id ?? "-"} from=${data?.from ?? "-"} seq=${data?.seq ?? "-"}`);
|
|
7957
|
-
|
|
8183
|
+
const groupId = isJsonObject(data) ? String(data.group_id ?? "").trim() : "";
|
|
8184
|
+
client._safeAsync(this.runPushProcessSerialized(groupId ? `group:${groupId}` : "", () => this.processAndPublishGroupMessage(data)));
|
|
7958
8185
|
client._clientLog.debug("_onRawGroupMessageCreated exit: elapsed=0ms (dispatched async)");
|
|
7959
8186
|
}
|
|
7960
8187
|
async processAndPublishGroupMessage(data) {
|
|
@@ -8911,6 +9138,9 @@ var MessageDeliveryEngine = class {
|
|
|
8911
9138
|
const client = this.runtime.client;
|
|
8912
9139
|
const seqNum = Number(seq);
|
|
8913
9140
|
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0 || !ns) {
|
|
9141
|
+
if (event === "message.recalled") {
|
|
9142
|
+
return this.publishMessageRecallTombstone(seq, payload);
|
|
9143
|
+
}
|
|
8914
9144
|
await client._publishAppEvent(event, payload);
|
|
8915
9145
|
return true;
|
|
8916
9146
|
}
|
|
@@ -8920,8 +9150,14 @@ var MessageDeliveryEngine = class {
|
|
|
8920
9150
|
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
8921
9151
|
return false;
|
|
8922
9152
|
}
|
|
9153
|
+
await this.drainOrderedMessages(ns, seqNum);
|
|
8923
9154
|
queue?.delete(seqNum);
|
|
8924
9155
|
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
9156
|
+
if (event === "message.recalled") {
|
|
9157
|
+
const published = await this.publishMessageRecallTombstone(seqNum, payload);
|
|
9158
|
+
this.markPublishedSeq(ns, seqNum);
|
|
9159
|
+
return published;
|
|
9160
|
+
}
|
|
8925
9161
|
await client._publishAppEvent(event, payload);
|
|
8926
9162
|
this.markPublishedSeq(ns, seqNum);
|
|
8927
9163
|
return true;
|
|
@@ -11083,6 +11319,346 @@ var GroupFSVFS = class {
|
|
|
11083
11319
|
}
|
|
11084
11320
|
};
|
|
11085
11321
|
|
|
11322
|
+
// src/v2/crypto/canonical.ts
|
|
11323
|
+
var encoder = new TextEncoder();
|
|
11324
|
+
var MAX_SAFE_JSON_INTEGER = 9007199254740991;
|
|
11325
|
+
function canonicalJson(obj) {
|
|
11326
|
+
return encoder.encode(serialize(obj));
|
|
11327
|
+
}
|
|
11328
|
+
function serialize(obj) {
|
|
11329
|
+
if (obj === null) return "null";
|
|
11330
|
+
if (obj === true) return "true";
|
|
11331
|
+
if (obj === false) return "false";
|
|
11332
|
+
if (typeof obj === "number") {
|
|
11333
|
+
return serializeNumber(obj);
|
|
11334
|
+
}
|
|
11335
|
+
if (typeof obj === "string") {
|
|
11336
|
+
return serializeString(obj);
|
|
11337
|
+
}
|
|
11338
|
+
if (Array.isArray(obj)) {
|
|
11339
|
+
return serializeArray(obj);
|
|
11340
|
+
}
|
|
11341
|
+
if (typeof obj === "object") {
|
|
11342
|
+
return serializeObject(obj);
|
|
11343
|
+
}
|
|
11344
|
+
throw new TypeError(`canonicalJson: unsupported type ${typeof obj}`);
|
|
11345
|
+
}
|
|
11346
|
+
function serializeNumber(n) {
|
|
11347
|
+
if (!isFinite(n)) {
|
|
11348
|
+
throw new RangeError("canonicalJson: Infinity and NaN not allowed");
|
|
11349
|
+
}
|
|
11350
|
+
if (Object.is(n, -0)) return "0";
|
|
11351
|
+
if (Number.isInteger(n)) {
|
|
11352
|
+
if (Math.abs(n) > MAX_SAFE_JSON_INTEGER) {
|
|
11353
|
+
throw new RangeError(`canonicalJson: integer outside safe range ${n}`);
|
|
11354
|
+
}
|
|
11355
|
+
return String(n);
|
|
11356
|
+
}
|
|
11357
|
+
return expandExponent(String(n));
|
|
11358
|
+
}
|
|
11359
|
+
function expandExponent(s) {
|
|
11360
|
+
if (!/[eE]/.test(s)) return s;
|
|
11361
|
+
const match = /^(-?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
|
|
11362
|
+
if (!match) {
|
|
11363
|
+
throw new TypeError(`canonicalJson: invalid number ${s}`);
|
|
11364
|
+
}
|
|
11365
|
+
const sign = match[1] ?? "";
|
|
11366
|
+
const intPart = match[2] ?? "";
|
|
11367
|
+
const fracPart = match[3] ?? "";
|
|
11368
|
+
const exp = Number(match[4]);
|
|
11369
|
+
const digits = intPart + fracPart;
|
|
11370
|
+
const point = intPart.length + exp;
|
|
11371
|
+
if (point <= 0) {
|
|
11372
|
+
return `${sign}0.${"0".repeat(-point)}${digits}`;
|
|
11373
|
+
}
|
|
11374
|
+
if (point >= digits.length) {
|
|
11375
|
+
return `${sign}${digits}${"0".repeat(point - digits.length)}`;
|
|
11376
|
+
}
|
|
11377
|
+
return `${sign}${digits.slice(0, point)}.${digits.slice(point)}`;
|
|
11378
|
+
}
|
|
11379
|
+
function serializeString(s) {
|
|
11380
|
+
let result = '"';
|
|
11381
|
+
for (let i = 0; i < s.length; i++) {
|
|
11382
|
+
const ch = s[i];
|
|
11383
|
+
const code = s.charCodeAt(i);
|
|
11384
|
+
if (ch === '"') {
|
|
11385
|
+
result += '\\"';
|
|
11386
|
+
} else if (ch === "\\") {
|
|
11387
|
+
result += "\\\\";
|
|
11388
|
+
} else if (ch === "\b") {
|
|
11389
|
+
result += "\\b";
|
|
11390
|
+
} else if (ch === "\f") {
|
|
11391
|
+
result += "\\f";
|
|
11392
|
+
} else if (ch === "\n") {
|
|
11393
|
+
result += "\\n";
|
|
11394
|
+
} else if (ch === "\r") {
|
|
11395
|
+
result += "\\r";
|
|
11396
|
+
} else if (ch === " ") {
|
|
11397
|
+
result += "\\t";
|
|
11398
|
+
} else if (code < 32) {
|
|
11399
|
+
result += "\\u" + code.toString(16).padStart(4, "0");
|
|
11400
|
+
} else {
|
|
11401
|
+
result += ch;
|
|
11402
|
+
}
|
|
11403
|
+
}
|
|
11404
|
+
result += '"';
|
|
11405
|
+
return result;
|
|
11406
|
+
}
|
|
11407
|
+
function serializeArray(arr) {
|
|
11408
|
+
const items = arr.map((item) => serialize(item));
|
|
11409
|
+
return "[" + items.join(",") + "]";
|
|
11410
|
+
}
|
|
11411
|
+
function serializeObject(obj) {
|
|
11412
|
+
const sortedKeys = Object.keys(obj).sort(compareCodePoints);
|
|
11413
|
+
const pairs = sortedKeys.map(
|
|
11414
|
+
(key) => serializeString(key) + ":" + serialize(obj[key])
|
|
11415
|
+
);
|
|
11416
|
+
return "{" + pairs.join(",") + "}";
|
|
11417
|
+
}
|
|
11418
|
+
function compareCodePoints(a, b) {
|
|
11419
|
+
const ac = Array.from(a);
|
|
11420
|
+
const bc = Array.from(b);
|
|
11421
|
+
const n = Math.min(ac.length, bc.length);
|
|
11422
|
+
for (let i = 0; i < n; i++) {
|
|
11423
|
+
const av = ac[i].codePointAt(0) ?? 0;
|
|
11424
|
+
const bv = bc[i].codePointAt(0) ?? 0;
|
|
11425
|
+
if (av !== bv) return av - bv;
|
|
11426
|
+
}
|
|
11427
|
+
return ac.length - bc.length;
|
|
11428
|
+
}
|
|
11429
|
+
|
|
11430
|
+
// src/group-index.ts
|
|
11431
|
+
var GROUP_INDEX_SCHEMA = "aun.group.index.v1";
|
|
11432
|
+
var GROUP_INDEX_KEY = "group.index";
|
|
11433
|
+
var GROUP_INDEX_SIG_ALG = "ECDSA-P256-SHA256";
|
|
11434
|
+
var GroupIndexMetaCache = class {
|
|
11435
|
+
constructor() {
|
|
11436
|
+
__publicField(this, "remote", /* @__PURE__ */ new Map());
|
|
11437
|
+
__publicField(this, "localEtags", /* @__PURE__ */ new Map());
|
|
11438
|
+
__publicField(this, "stale", /* @__PURE__ */ new Set());
|
|
11439
|
+
__publicField(this, "settings", /* @__PURE__ */ new Map());
|
|
11440
|
+
__publicField(this, "entryEtags", /* @__PURE__ */ new Map());
|
|
11441
|
+
}
|
|
11442
|
+
observeRpcMeta(meta, options) {
|
|
11443
|
+
const groupIndexes = isRecord4(meta?.group_indexes) ? meta.group_indexes : null;
|
|
11444
|
+
if (!groupIndexes) return;
|
|
11445
|
+
const local = String(options.localAid ?? "");
|
|
11446
|
+
for (const [groupAid, value] of Object.entries(groupIndexes)) {
|
|
11447
|
+
if (!isRecord4(value)) continue;
|
|
11448
|
+
const key = this.key(local, groupAid);
|
|
11449
|
+
const remoteMeta = {};
|
|
11450
|
+
for (const name of ["etag", "last_modified", "schema"]) {
|
|
11451
|
+
if (value[name] !== void 0 && value[name] !== null) remoteMeta[name] = value[name];
|
|
11452
|
+
}
|
|
11453
|
+
this.remote.set(key, remoteMeta);
|
|
11454
|
+
const remoteEtag = String(remoteMeta.etag ?? "");
|
|
11455
|
+
if (remoteEtag && this.localEtags.get(key) !== remoteEtag) this.stale.add(key);
|
|
11456
|
+
}
|
|
11457
|
+
}
|
|
11458
|
+
markFresh(localAid, groupAid, options) {
|
|
11459
|
+
const key = this.key(localAid, groupAid);
|
|
11460
|
+
this.localEtags.set(key, String(options.etag ?? ""));
|
|
11461
|
+
this.stale.delete(key);
|
|
11462
|
+
}
|
|
11463
|
+
isStale(localAid, groupAid) {
|
|
11464
|
+
return this.stale.has(this.key(localAid, groupAid));
|
|
11465
|
+
}
|
|
11466
|
+
remoteMeta(localAid, groupAid) {
|
|
11467
|
+
const value = this.remote.get(this.key(localAid, groupAid));
|
|
11468
|
+
return value ? { ...value } : null;
|
|
11469
|
+
}
|
|
11470
|
+
localEtag(localAid, groupAid) {
|
|
11471
|
+
return this.localEtags.get(this.key(localAid, groupAid)) ?? "";
|
|
11472
|
+
}
|
|
11473
|
+
cachedSettings(localAid, groupAid, keys) {
|
|
11474
|
+
const value = this.settings.get(this.key(localAid, groupAid)) ?? {};
|
|
11475
|
+
if (!keys.every((item) => item in value)) return null;
|
|
11476
|
+
return Object.fromEntries(keys.map((item) => [item, value[item]]));
|
|
11477
|
+
}
|
|
11478
|
+
cachedSettingsByEntries(localAid, groupAid, keys, entries) {
|
|
11479
|
+
const key = this.key(localAid, groupAid);
|
|
11480
|
+
const value = this.settings.get(key) ?? {};
|
|
11481
|
+
const localEntryEtags = this.entryEtags.get(key) ?? {};
|
|
11482
|
+
const remoteEntryEtags = Object.fromEntries(entries.map((item) => [String(item.key ?? ""), String(item.etag ?? "")]));
|
|
11483
|
+
const cached = {};
|
|
11484
|
+
const missing = [];
|
|
11485
|
+
for (const item of keys) {
|
|
11486
|
+
if (item in value && localEntryEtags[item] === remoteEntryEtags[item]) {
|
|
11487
|
+
cached[item] = value[item];
|
|
11488
|
+
} else {
|
|
11489
|
+
missing.push(item);
|
|
11490
|
+
}
|
|
11491
|
+
}
|
|
11492
|
+
return { cached, missing };
|
|
11493
|
+
}
|
|
11494
|
+
cacheSettings(localAid, groupAid, settings, options) {
|
|
11495
|
+
const key = this.key(localAid, groupAid);
|
|
11496
|
+
this.settings.set(key, { ...this.settings.get(key) ?? {}, ...settings });
|
|
11497
|
+
if (options?.entries) {
|
|
11498
|
+
const nextEntryEtags = { ...this.entryEtags.get(key) ?? {} };
|
|
11499
|
+
for (const item of options.entries) {
|
|
11500
|
+
const entryKey = String(item.key ?? "");
|
|
11501
|
+
if (entryKey) nextEntryEtags[entryKey] = String(item.etag ?? "");
|
|
11502
|
+
}
|
|
11503
|
+
this.entryEtags.set(key, nextEntryEtags);
|
|
11504
|
+
}
|
|
11505
|
+
if (options?.etag) this.markFresh(localAid, groupAid, { etag: options.etag });
|
|
11506
|
+
}
|
|
11507
|
+
restore(localAid, groupAid, record) {
|
|
11508
|
+
const key = this.key(localAid, groupAid);
|
|
11509
|
+
if (isRecord4(record.remote_meta)) this.remote.set(key, { ...record.remote_meta });
|
|
11510
|
+
if (record.local_etag !== void 0 && record.local_etag !== null) {
|
|
11511
|
+
this.localEtags.set(key, String(record.local_etag ?? ""));
|
|
11512
|
+
}
|
|
11513
|
+
if (isRecord4(record.settings)) this.settings.set(key, { ...this.settings.get(key) ?? {}, ...record.settings });
|
|
11514
|
+
if (isRecord4(record.entry_etags)) {
|
|
11515
|
+
this.entryEtags.set(key, {
|
|
11516
|
+
...this.entryEtags.get(key) ?? {},
|
|
11517
|
+
...Object.fromEntries(Object.entries(record.entry_etags).map(([entryKey, entryEtag]) => [entryKey, String(entryEtag ?? "")]))
|
|
11518
|
+
});
|
|
11519
|
+
}
|
|
11520
|
+
const remoteEtag = String(this.remote.get(key)?.etag ?? "");
|
|
11521
|
+
if (remoteEtag && this.localEtags.get(key) !== remoteEtag) this.stale.add(key);
|
|
11522
|
+
if (remoteEtag && this.localEtags.get(key) === remoteEtag) this.stale.delete(key);
|
|
11523
|
+
}
|
|
11524
|
+
key(localAid, groupAid) {
|
|
11525
|
+
return `${String(localAid ?? "")}\0${String(groupAid ?? "")}`;
|
|
11526
|
+
}
|
|
11527
|
+
};
|
|
11528
|
+
async function computeGroupIndexBodyHash(entries) {
|
|
11529
|
+
return `sha256:${await sha256Hex2(entriesBytes(entries))}`;
|
|
11530
|
+
}
|
|
11531
|
+
async function groupIndexEtag(entries) {
|
|
11532
|
+
return `"sha256:${await sha256Hex2(entriesBytes(entries))}"`;
|
|
11533
|
+
}
|
|
11534
|
+
function groupIndexSigningPayload(meta, entries) {
|
|
11535
|
+
const metaWithoutSignature = { ...meta };
|
|
11536
|
+
delete metaWithoutSignature.signature;
|
|
11537
|
+
const lines = [canonicalStringify(metaWithoutSignature)];
|
|
11538
|
+
lines.push(...canonicalEntries(entries).map((item) => canonicalStringify(item)));
|
|
11539
|
+
return encode(`${lines.join("\n")}
|
|
11540
|
+
`);
|
|
11541
|
+
}
|
|
11542
|
+
async function buildSignedGroupIndex(options) {
|
|
11543
|
+
const entries = canonicalEntries(options.entries);
|
|
11544
|
+
const meta = {
|
|
11545
|
+
type: "index_meta",
|
|
11546
|
+
group_aid: String(options.groupAid),
|
|
11547
|
+
etag: await groupIndexEtag(entries),
|
|
11548
|
+
last_modified: Math.trunc(Number(options.lastModified)),
|
|
11549
|
+
schema: String(options.schema ?? GROUP_INDEX_SCHEMA),
|
|
11550
|
+
body_hash: await computeGroupIndexBodyHash(entries),
|
|
11551
|
+
signed_by: options.signer.aid,
|
|
11552
|
+
sig_alg: GROUP_INDEX_SIG_ALG
|
|
11553
|
+
};
|
|
11554
|
+
const signed = await options.signer.sign(groupIndexSigningPayload(meta, entries));
|
|
11555
|
+
if (!signed.ok) throw new Error(signed.error.message || "group index signing failed");
|
|
11556
|
+
meta.signature = signed.data.signature;
|
|
11557
|
+
const body = [canonicalStringify(meta), ...entries.map((item) => canonicalStringify(item))].join("\n") + "\n";
|
|
11558
|
+
return { body, meta, entries };
|
|
11559
|
+
}
|
|
11560
|
+
function parseGroupIndex(body) {
|
|
11561
|
+
const text3 = typeof body === "string" ? body : String(body?.body ?? "");
|
|
11562
|
+
const lines = text3.split(/\r?\n/).filter((line) => line.trim());
|
|
11563
|
+
if (lines.length === 0) throw new Error("group index body is empty");
|
|
11564
|
+
const meta = JSON.parse(lines[0]);
|
|
11565
|
+
const entries = lines.slice(1).map((line) => JSON.parse(line));
|
|
11566
|
+
if (meta.type !== "index_meta") throw new Error("first group index line must be index_meta");
|
|
11567
|
+
return { meta, entries };
|
|
11568
|
+
}
|
|
11569
|
+
async function verifyGroupIndex(body, signer) {
|
|
11570
|
+
try {
|
|
11571
|
+
const parsed = parseGroupIndex(body);
|
|
11572
|
+
const signature = String(parsed.meta.signature ?? "");
|
|
11573
|
+
if (!signature) return resultOk({ valid: false, reason: "signature missing" });
|
|
11574
|
+
if (String(parsed.meta.signed_by ?? "") !== signer.aid) return resultOk({ valid: false, reason: "signed_by mismatch" });
|
|
11575
|
+
if (String(parsed.meta.sig_alg ?? "") !== GROUP_INDEX_SIG_ALG) return resultOk({ valid: false, reason: "unsupported sig_alg" });
|
|
11576
|
+
if (String(parsed.meta.body_hash ?? "") !== await computeGroupIndexBodyHash(parsed.entries)) {
|
|
11577
|
+
return resultOk({ valid: false, reason: "body_hash mismatch" });
|
|
11578
|
+
}
|
|
11579
|
+
if (String(parsed.meta.etag ?? "") !== await groupIndexEtag(parsed.entries)) {
|
|
11580
|
+
return resultOk({ valid: false, reason: "etag mismatch" });
|
|
11581
|
+
}
|
|
11582
|
+
const verified = await signer.verify(groupIndexSigningPayload(parsed.meta, parsed.entries), signature);
|
|
11583
|
+
if (!verified.ok) return resultErr(verified.error.code, verified.error.message || "group index verify failed", verified.error.cause);
|
|
11584
|
+
if (!verified.data.valid) return resultOk({ valid: false, reason: "signature verification failed" });
|
|
11585
|
+
return resultOk({ valid: true, meta: parsed.meta, entries: canonicalEntries(parsed.entries) });
|
|
11586
|
+
} catch (exc) {
|
|
11587
|
+
return resultErr("GROUP_INDEX_VERIFY_ERROR", String(exc), exc);
|
|
11588
|
+
}
|
|
11589
|
+
}
|
|
11590
|
+
async function prepareGroupSettingsWithIndex(options) {
|
|
11591
|
+
const result = { ...options.settings };
|
|
11592
|
+
const updatedEntries = [];
|
|
11593
|
+
for (const [key, value] of Object.entries(options.settings)) {
|
|
11594
|
+
if (key !== GROUP_INDEX_KEY) updatedEntries.push(await settingEntry(key, value, options.lastModified));
|
|
11595
|
+
}
|
|
11596
|
+
const updatedKeys = new Set(updatedEntries.map((item) => item.key));
|
|
11597
|
+
const entries = [];
|
|
11598
|
+
if (options.baseIndex) {
|
|
11599
|
+
const parsed = parseGroupIndex(options.baseIndex);
|
|
11600
|
+
entries.push(...parsed.entries.filter((item) => !updatedKeys.has(String(item.key))).map((item) => ({ ...item })));
|
|
11601
|
+
}
|
|
11602
|
+
entries.push(...updatedEntries);
|
|
11603
|
+
result[GROUP_INDEX_KEY] = await buildSignedGroupIndex({
|
|
11604
|
+
groupAid: options.groupAid,
|
|
11605
|
+
entries,
|
|
11606
|
+
signer: options.signer,
|
|
11607
|
+
lastModified: options.lastModified
|
|
11608
|
+
});
|
|
11609
|
+
return result;
|
|
11610
|
+
}
|
|
11611
|
+
async function settingEntry(key, value, lastModified) {
|
|
11612
|
+
const digest = await sha256Hex2(encode(canonicalStringify(value)));
|
|
11613
|
+
return {
|
|
11614
|
+
key,
|
|
11615
|
+
source: "db",
|
|
11616
|
+
etag: `"sha256:${digest}"`,
|
|
11617
|
+
last_modified: Math.trunc(Number(lastModified))
|
|
11618
|
+
};
|
|
11619
|
+
}
|
|
11620
|
+
function canonicalEntries(entries) {
|
|
11621
|
+
return entries.map((item) => ({ ...item })).sort((a, b) => compareCodePoints2(String(a.key ?? ""), String(b.key ?? "")));
|
|
11622
|
+
}
|
|
11623
|
+
function entriesBytes(entries) {
|
|
11624
|
+
const lines = canonicalEntries(entries).map((item) => canonicalStringify(item));
|
|
11625
|
+
return encode(lines.length ? `${lines.join("\n")}
|
|
11626
|
+
` : "");
|
|
11627
|
+
}
|
|
11628
|
+
function canonicalStringify(value) {
|
|
11629
|
+
return new TextDecoder().decode(canonicalJson(value));
|
|
11630
|
+
}
|
|
11631
|
+
function encode(text3) {
|
|
11632
|
+
return new TextEncoder().encode(text3);
|
|
11633
|
+
}
|
|
11634
|
+
async function sha256Hex2(data) {
|
|
11635
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", exactArrayBuffer(data));
|
|
11636
|
+
return bytesToHex(new Uint8Array(digest));
|
|
11637
|
+
}
|
|
11638
|
+
function exactArrayBuffer(data) {
|
|
11639
|
+
if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength && data.buffer instanceof ArrayBuffer) {
|
|
11640
|
+
return data.buffer;
|
|
11641
|
+
}
|
|
11642
|
+
return data.slice().buffer;
|
|
11643
|
+
}
|
|
11644
|
+
function bytesToHex(bytes) {
|
|
11645
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
11646
|
+
}
|
|
11647
|
+
function compareCodePoints2(a, b) {
|
|
11648
|
+
const ac = Array.from(a);
|
|
11649
|
+
const bc = Array.from(b);
|
|
11650
|
+
const n = Math.min(ac.length, bc.length);
|
|
11651
|
+
for (let i = 0; i < n; i++) {
|
|
11652
|
+
const av = ac[i].codePointAt(0) ?? 0;
|
|
11653
|
+
const bv = bc[i].codePointAt(0) ?? 0;
|
|
11654
|
+
if (av !== bv) return av - bv;
|
|
11655
|
+
}
|
|
11656
|
+
return ac.length - bc.length;
|
|
11657
|
+
}
|
|
11658
|
+
function isRecord4(value) {
|
|
11659
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
11660
|
+
}
|
|
11661
|
+
|
|
11086
11662
|
// src/facades.ts
|
|
11087
11663
|
function stripNil2(params2) {
|
|
11088
11664
|
const out = {};
|
|
@@ -11105,6 +11681,13 @@ function settingsToMap(result) {
|
|
|
11105
11681
|
}
|
|
11106
11682
|
return settings;
|
|
11107
11683
|
}
|
|
11684
|
+
function indexUpdateParams(groupId, settings, merged) {
|
|
11685
|
+
const out = { group_id: groupId, settings };
|
|
11686
|
+
for (const key of ["signer", "last_modified", "max_attempts"]) {
|
|
11687
|
+
if (key in merged) out[key] = merged[key];
|
|
11688
|
+
}
|
|
11689
|
+
return out;
|
|
11690
|
+
}
|
|
11108
11691
|
var RpcFacade = class {
|
|
11109
11692
|
constructor(client) {
|
|
11110
11693
|
__publicField(this, "client");
|
|
@@ -11277,6 +11860,174 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11277
11860
|
getSettings(params2) {
|
|
11278
11861
|
return this.call("group.get_settings", params2);
|
|
11279
11862
|
}
|
|
11863
|
+
async checkGroupIndex(params2) {
|
|
11864
|
+
const merged = stripNil2(params2);
|
|
11865
|
+
const groupAid = String(merged.group_aid ?? merged.group_id ?? "").trim();
|
|
11866
|
+
if (!groupAid) throw new Error("group_aid is required");
|
|
11867
|
+
const clientAny = this.client;
|
|
11868
|
+
const stale = typeof clientAny.isGroupIndexStale === "function" ? Boolean(clientAny.isGroupIndexStale(groupAid)) : false;
|
|
11869
|
+
const remoteMeta = typeof clientAny.getGroupIndexRemoteMeta === "function" ? clientAny.getGroupIndexRemoteMeta(groupAid) ?? {} : {};
|
|
11870
|
+
const localEtag = typeof clientAny.getGroupIndexLocalEtag === "function" ? String(clientAny.getGroupIndexLocalEtag(groupAid) ?? "") : "";
|
|
11871
|
+
const remoteEtag = String(remoteMeta?.etag ?? "");
|
|
11872
|
+
const localFound = Boolean(localEtag);
|
|
11873
|
+
const remoteFound = Boolean(remoteEtag);
|
|
11874
|
+
const inSync = localFound && remoteFound && localEtag === remoteEtag;
|
|
11875
|
+
return {
|
|
11876
|
+
group_aid: groupAid,
|
|
11877
|
+
local_found: localFound,
|
|
11878
|
+
remote_found: remoteFound,
|
|
11879
|
+
local_etag: localEtag,
|
|
11880
|
+
remote_etag: remoteEtag,
|
|
11881
|
+
in_sync: inSync,
|
|
11882
|
+
needs_update: Boolean(stale || remoteFound && !inSync),
|
|
11883
|
+
last_modified: remoteMeta?.last_modified,
|
|
11884
|
+
status: remoteFound ? 200 : 404,
|
|
11885
|
+
cached: true
|
|
11886
|
+
};
|
|
11887
|
+
}
|
|
11888
|
+
async getGroupIndex(params2) {
|
|
11889
|
+
const merged = stripNil2(params2);
|
|
11890
|
+
const groupId = String(merged.group_id ?? "").trim();
|
|
11891
|
+
if (!groupId) throw new Error("group_id is required");
|
|
11892
|
+
const result = await this.getSettings({ group_id: groupId, keys: [GROUP_INDEX_KEY] });
|
|
11893
|
+
const groupAid = String(result.group_aid ?? groupId);
|
|
11894
|
+
let groupIndex = null;
|
|
11895
|
+
for (const item of result.settings ?? []) {
|
|
11896
|
+
if (item?.key !== GROUP_INDEX_KEY) continue;
|
|
11897
|
+
groupIndex = item.value;
|
|
11898
|
+
break;
|
|
11899
|
+
}
|
|
11900
|
+
if (!groupIndex) {
|
|
11901
|
+
return { group_id: result.group_id, group_aid: groupAid, group_index: null, meta: {}, entries: [] };
|
|
11902
|
+
}
|
|
11903
|
+
const parsed = parseGroupIndex(groupIndex);
|
|
11904
|
+
await this.verifyPulledGroupIndex(groupIndex, parsed);
|
|
11905
|
+
const etag = String(parsed.meta.etag ?? "");
|
|
11906
|
+
const settings = await this.hydrateGroupIndexSettings(groupId, groupAid, parsed.entries, etag, groupIndex);
|
|
11907
|
+
const clientAny = this.client;
|
|
11908
|
+
if (etag && typeof clientAny.markGroupIndexFresh === "function") {
|
|
11909
|
+
clientAny.markGroupIndexFresh(groupAid, { etag });
|
|
11910
|
+
}
|
|
11911
|
+
return {
|
|
11912
|
+
group_id: result.group_id,
|
|
11913
|
+
group_aid: groupAid,
|
|
11914
|
+
group_index: groupIndex,
|
|
11915
|
+
meta: parsed.meta,
|
|
11916
|
+
entries: parsed.entries,
|
|
11917
|
+
settings
|
|
11918
|
+
};
|
|
11919
|
+
}
|
|
11920
|
+
async verifyPulledGroupIndex(groupIndex, parsed) {
|
|
11921
|
+
const signedBy = String(parsed.meta?.signed_by ?? "").trim();
|
|
11922
|
+
if (!signedBy) throw new Error("group.index signed_by is required");
|
|
11923
|
+
const clientAny = this.client;
|
|
11924
|
+
let signer = clientAny.currentAid?.aid === signedBy ? clientAny.currentAid : null;
|
|
11925
|
+
if (!signer && typeof clientAny.lookupPeer === "function") {
|
|
11926
|
+
signer = await clientAny.lookupPeer(signedBy);
|
|
11927
|
+
}
|
|
11928
|
+
if (!signer) throw new Error(`group.index signer is unavailable: ${signedBy}`);
|
|
11929
|
+
const verified = await verifyGroupIndex(groupIndex, signer);
|
|
11930
|
+
if (!verified.ok) throw new Error(verified.error.message || "group.index verification failed");
|
|
11931
|
+
if (!verified.data.valid) throw new Error(`group.index verification failed: ${verified.data.reason || "invalid signature"}`);
|
|
11932
|
+
}
|
|
11933
|
+
async updateGroupIndex(params2) {
|
|
11934
|
+
const merged = stripNil2(params2);
|
|
11935
|
+
const groupId = String(merged.group_id ?? "").trim();
|
|
11936
|
+
const settings = merged.settings;
|
|
11937
|
+
if (!groupId) throw new Error("group_id is required");
|
|
11938
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings) || Object.keys(settings).length === 0) {
|
|
11939
|
+
throw new Error("settings must be a non-empty object");
|
|
11940
|
+
}
|
|
11941
|
+
const signer = merged.signer ?? this.client.currentAid;
|
|
11942
|
+
if (!signer) throw new Error("signer is required");
|
|
11943
|
+
const lastModified = Math.trunc(Number(merged.last_modified ?? Date.now()));
|
|
11944
|
+
const maxAttempts = Math.max(1, Math.trunc(Number(merged.max_attempts ?? 2)));
|
|
11945
|
+
let lastError = null;
|
|
11946
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
11947
|
+
const current = await this.getSettings({ group_id: groupId, keys: [GROUP_INDEX_KEY] });
|
|
11948
|
+
const groupAid = String(current.group_aid ?? groupId);
|
|
11949
|
+
let currentIndex = null;
|
|
11950
|
+
let expectedEtag = "";
|
|
11951
|
+
for (const item of current.settings ?? []) {
|
|
11952
|
+
if (item?.key !== GROUP_INDEX_KEY) continue;
|
|
11953
|
+
currentIndex = item.value;
|
|
11954
|
+
if (currentIndex) expectedEtag = String(parseGroupIndex(currentIndex).meta.etag ?? "");
|
|
11955
|
+
break;
|
|
11956
|
+
}
|
|
11957
|
+
const signedSettings = await prepareGroupSettingsWithIndex({
|
|
11958
|
+
groupAid,
|
|
11959
|
+
settings,
|
|
11960
|
+
signer,
|
|
11961
|
+
lastModified,
|
|
11962
|
+
baseIndex: currentIndex
|
|
11963
|
+
});
|
|
11964
|
+
try {
|
|
11965
|
+
const result = await this.setSettings({
|
|
11966
|
+
group_id: groupId,
|
|
11967
|
+
settings: signedSettings,
|
|
11968
|
+
expected_index_etag: expectedEtag
|
|
11969
|
+
});
|
|
11970
|
+
const pushedEtag = String(parseGroupIndex(signedSettings[GROUP_INDEX_KEY]).meta.etag ?? "");
|
|
11971
|
+
const clientAny = this.client;
|
|
11972
|
+
if (pushedEtag && typeof clientAny.markGroupIndexFresh === "function") {
|
|
11973
|
+
clientAny.markGroupIndexFresh(groupAid, { etag: pushedEtag });
|
|
11974
|
+
}
|
|
11975
|
+
if (typeof clientAny.cacheGroupIndexSettings === "function") {
|
|
11976
|
+
const parsed = parseGroupIndex(signedSettings[GROUP_INDEX_KEY]);
|
|
11977
|
+
await clientAny.cacheGroupIndexSettings(groupAid, settings, {
|
|
11978
|
+
entries: parsed.entries,
|
|
11979
|
+
etag: pushedEtag,
|
|
11980
|
+
groupIndex: signedSettings[GROUP_INDEX_KEY]
|
|
11981
|
+
});
|
|
11982
|
+
}
|
|
11983
|
+
return result;
|
|
11984
|
+
} catch (exc) {
|
|
11985
|
+
if (!String(exc?.message ?? exc).includes("etag conflict")) throw exc;
|
|
11986
|
+
lastError = exc;
|
|
11987
|
+
}
|
|
11988
|
+
}
|
|
11989
|
+
if (lastError) throw lastError;
|
|
11990
|
+
throw new Error("updateGroupIndex failed");
|
|
11991
|
+
}
|
|
11992
|
+
async getIndexedSettings(groupId, keys) {
|
|
11993
|
+
const clientAny = this.client;
|
|
11994
|
+
if (typeof clientAny.getGroupIndexCachedSettings === "function") {
|
|
11995
|
+
const cached = await clientAny.getGroupIndexCachedSettings(groupId, keys);
|
|
11996
|
+
if (cached && typeof cached === "object") return { groupId, settings: cached };
|
|
11997
|
+
}
|
|
11998
|
+
const result = await this.getSettings({ group_id: groupId, keys });
|
|
11999
|
+
const resultMap = result;
|
|
12000
|
+
const settings = settingsToMap(result);
|
|
12001
|
+
if (typeof clientAny.cacheGroupIndexSettings === "function") {
|
|
12002
|
+
const groupAid = String(resultMap.group_aid ?? groupId);
|
|
12003
|
+
await clientAny.cacheGroupIndexSettings(groupAid, settings);
|
|
12004
|
+
if (groupAid !== groupId) {
|
|
12005
|
+
await clientAny.cacheGroupIndexSettings(groupId, settings);
|
|
12006
|
+
}
|
|
12007
|
+
}
|
|
12008
|
+
return { groupId: String(resultMap.group_id ?? groupId), settings };
|
|
12009
|
+
}
|
|
12010
|
+
async hydrateGroupIndexSettings(groupId, groupAid, entries, etag, groupIndex) {
|
|
12011
|
+
const keys = entries.filter((item) => String(item.source ?? "db") === "db" && String(item.key ?? "")).map((item) => String(item.key));
|
|
12012
|
+
if (keys.length === 0) return {};
|
|
12013
|
+
const clientAny = this.client;
|
|
12014
|
+
let cached = {};
|
|
12015
|
+
let missing = [...keys];
|
|
12016
|
+
if (typeof clientAny.getGroupIndexCachedSettingsByEntries === "function") {
|
|
12017
|
+
const value = await clientAny.getGroupIndexCachedSettingsByEntries(groupAid, keys, entries);
|
|
12018
|
+
cached = { ...value?.cached ?? {} };
|
|
12019
|
+
missing = [...value?.missing ?? []].map((item) => String(item));
|
|
12020
|
+
}
|
|
12021
|
+
let fetched = {};
|
|
12022
|
+
if (missing.length > 0) {
|
|
12023
|
+
fetched = settingsToMap(await this.getSettings({ group_id: groupId, keys: missing }));
|
|
12024
|
+
}
|
|
12025
|
+
const settings = { ...cached, ...fetched };
|
|
12026
|
+
if (typeof clientAny.cacheGroupIndexSettings === "function") {
|
|
12027
|
+
await clientAny.cacheGroupIndexSettings(groupAid, settings, { entries, etag, groupIndex });
|
|
12028
|
+
}
|
|
12029
|
+
return settings;
|
|
12030
|
+
}
|
|
11280
12031
|
send(params2) {
|
|
11281
12032
|
validateGroupIDFormat(params2?.group_id, "group_id");
|
|
11282
12033
|
return this.call("group.send", params2);
|
|
@@ -11301,15 +12052,14 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11301
12052
|
const merged = params2 || {};
|
|
11302
12053
|
const groupId = merged.group_id;
|
|
11303
12054
|
if (!groupId) throw new Error("group_id is required");
|
|
11304
|
-
const
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
const settings = settingsToMap(result);
|
|
12055
|
+
const { groupId: resultGroupId, settings } = await this.getIndexedSettings(
|
|
12056
|
+
String(groupId),
|
|
12057
|
+
["announcement.content", "announcement.attachments"]
|
|
12058
|
+
);
|
|
11309
12059
|
return {
|
|
11310
|
-
group_id:
|
|
12060
|
+
group_id: resultGroupId,
|
|
11311
12061
|
announcement: {
|
|
11312
|
-
group_id:
|
|
12062
|
+
group_id: resultGroupId,
|
|
11313
12063
|
content: settings["announcement.content"] || "",
|
|
11314
12064
|
attachments: settings["announcement.attachments"] || [],
|
|
11315
12065
|
updated_by: settings["announcement.content.updated_by"] || "",
|
|
@@ -11328,10 +12078,7 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11328
12078
|
if (attachments !== void 0) {
|
|
11329
12079
|
settingsUpdate["announcement.attachments"] = attachments;
|
|
11330
12080
|
}
|
|
11331
|
-
const result = await this.
|
|
11332
|
-
group_id: groupId,
|
|
11333
|
-
settings: settingsUpdate
|
|
11334
|
-
});
|
|
12081
|
+
const result = await this.updateGroupIndex(indexUpdateParams(groupId, settingsUpdate, merged));
|
|
11335
12082
|
return {
|
|
11336
12083
|
group_id: result.group_id,
|
|
11337
12084
|
announcement: {
|
|
@@ -11345,15 +12092,14 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11345
12092
|
const merged = params2 || {};
|
|
11346
12093
|
const groupId = merged.group_id;
|
|
11347
12094
|
if (!groupId) throw new Error("group_id is required");
|
|
11348
|
-
const
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
const settings = settingsToMap(result);
|
|
12095
|
+
const { groupId: resultGroupId, settings } = await this.getIndexedSettings(
|
|
12096
|
+
String(groupId),
|
|
12097
|
+
["rules.content", "rules.attachments"]
|
|
12098
|
+
);
|
|
11353
12099
|
return {
|
|
11354
|
-
group_id:
|
|
12100
|
+
group_id: resultGroupId,
|
|
11355
12101
|
rules: {
|
|
11356
|
-
group_id:
|
|
12102
|
+
group_id: resultGroupId,
|
|
11357
12103
|
content: settings["rules.content"] || "",
|
|
11358
12104
|
attachments: settings["rules.attachments"] || [],
|
|
11359
12105
|
updated_by: settings["rules.content.updated_by"] || "",
|
|
@@ -11372,10 +12118,7 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11372
12118
|
if (attachments !== void 0) {
|
|
11373
12119
|
settingsUpdate["rules.attachments"] = attachments;
|
|
11374
12120
|
}
|
|
11375
|
-
const result = await this.
|
|
11376
|
-
group_id: groupId,
|
|
11377
|
-
settings: settingsUpdate
|
|
11378
|
-
});
|
|
12121
|
+
const result = await this.updateGroupIndex(indexUpdateParams(groupId, settingsUpdate, merged));
|
|
11379
12122
|
return {
|
|
11380
12123
|
group_id: result.group_id,
|
|
11381
12124
|
rules: {
|
|
@@ -11389,15 +12132,14 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11389
12132
|
const merged = params2 || {};
|
|
11390
12133
|
const groupId = merged.group_id;
|
|
11391
12134
|
if (!groupId) throw new Error("group_id is required");
|
|
11392
|
-
const
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
const settings = settingsToMap(result);
|
|
12135
|
+
const { groupId: resultGroupId, settings } = await this.getIndexedSettings(
|
|
12136
|
+
String(groupId),
|
|
12137
|
+
["join.mode", "join.question", "join.auto_approve_patterns", "join.max_pending"]
|
|
12138
|
+
);
|
|
11397
12139
|
return {
|
|
11398
|
-
group_id:
|
|
12140
|
+
group_id: resultGroupId,
|
|
11399
12141
|
join_requirements: {
|
|
11400
|
-
group_id:
|
|
12142
|
+
group_id: resultGroupId,
|
|
11401
12143
|
mode: settings["join.mode"] || "open",
|
|
11402
12144
|
question: settings["join.question"] || "",
|
|
11403
12145
|
auto_approve_patterns: settings["join.auto_approve_patterns"] || [],
|
|
@@ -11419,10 +12161,7 @@ var GroupFacade = class extends RpcFacade {
|
|
|
11419
12161
|
if (Object.keys(settingsUpdate).length === 0) {
|
|
11420
12162
|
throw new Error("at least one field to update is required");
|
|
11421
12163
|
}
|
|
11422
|
-
const result = await this.
|
|
11423
|
-
group_id: groupId,
|
|
11424
|
-
settings: settingsUpdate
|
|
11425
|
-
});
|
|
12164
|
+
const result = await this.updateGroupIndex(indexUpdateParams(groupId, settingsUpdate, merged));
|
|
11426
12165
|
return {
|
|
11427
12166
|
group_id: result.group_id,
|
|
11428
12167
|
join_requirements: {
|
|
@@ -11558,7 +12297,7 @@ function unmountFromAny(input, fallback) {
|
|
|
11558
12297
|
}
|
|
11559
12298
|
|
|
11560
12299
|
// src/storage/vfs.ts
|
|
11561
|
-
async function
|
|
12300
|
+
async function sha256Hex3(data) {
|
|
11562
12301
|
const copy = new Uint8Array(data.byteLength);
|
|
11563
12302
|
copy.set(data);
|
|
11564
12303
|
const subtle = globalThis.crypto?.subtle;
|
|
@@ -11610,7 +12349,7 @@ var StorageVFS = class {
|
|
|
11610
12349
|
const owner = this.owner(options.owner);
|
|
11611
12350
|
const bucket = options.bucket ?? "default";
|
|
11612
12351
|
const objectKey = pathToKey(path);
|
|
11613
|
-
const sha2566 = await
|
|
12352
|
+
const sha2566 = await sha256Hex3(data);
|
|
11614
12353
|
const overwrite = options.overwrite ?? false;
|
|
11615
12354
|
try {
|
|
11616
12355
|
const check = await this.lowlevel.checkUpload({ owner, bucket, objectKey, size: data.length, sha256: sha2566 });
|
|
@@ -11706,7 +12445,7 @@ var StorageVFS = class {
|
|
|
11706
12445
|
}
|
|
11707
12446
|
async downloadFile(path, options = {}) {
|
|
11708
12447
|
const { data, sha256: expectedSha } = await this.readBytesWithMetadata(path, options);
|
|
11709
|
-
const actualSha = await
|
|
12448
|
+
const actualSha = await sha256Hex3(data);
|
|
11710
12449
|
const expected = expectedSha.toLowerCase();
|
|
11711
12450
|
const verified = Boolean(expected) && actualSha.toLowerCase() === expected;
|
|
11712
12451
|
if (!verified && expected && (options.verifyHash ?? true)) {
|
|
@@ -12192,114 +12931,6 @@ init_crypto();
|
|
|
12192
12931
|
// src/v2/e2ee/types.ts
|
|
12193
12932
|
var SUITE_NAME = "P256_HKDF_SHA256_AES_256_GCM";
|
|
12194
12933
|
|
|
12195
|
-
// src/v2/crypto/canonical.ts
|
|
12196
|
-
var encoder = new TextEncoder();
|
|
12197
|
-
var MAX_SAFE_JSON_INTEGER = 9007199254740991;
|
|
12198
|
-
function canonicalJson(obj) {
|
|
12199
|
-
return encoder.encode(serialize(obj));
|
|
12200
|
-
}
|
|
12201
|
-
function serialize(obj) {
|
|
12202
|
-
if (obj === null) return "null";
|
|
12203
|
-
if (obj === true) return "true";
|
|
12204
|
-
if (obj === false) return "false";
|
|
12205
|
-
if (typeof obj === "number") {
|
|
12206
|
-
return serializeNumber(obj);
|
|
12207
|
-
}
|
|
12208
|
-
if (typeof obj === "string") {
|
|
12209
|
-
return serializeString(obj);
|
|
12210
|
-
}
|
|
12211
|
-
if (Array.isArray(obj)) {
|
|
12212
|
-
return serializeArray(obj);
|
|
12213
|
-
}
|
|
12214
|
-
if (typeof obj === "object") {
|
|
12215
|
-
return serializeObject(obj);
|
|
12216
|
-
}
|
|
12217
|
-
throw new TypeError(`canonicalJson: unsupported type ${typeof obj}`);
|
|
12218
|
-
}
|
|
12219
|
-
function serializeNumber(n) {
|
|
12220
|
-
if (!isFinite(n)) {
|
|
12221
|
-
throw new RangeError("canonicalJson: Infinity and NaN not allowed");
|
|
12222
|
-
}
|
|
12223
|
-
if (Object.is(n, -0)) return "0";
|
|
12224
|
-
if (Number.isInteger(n)) {
|
|
12225
|
-
if (Math.abs(n) > MAX_SAFE_JSON_INTEGER) {
|
|
12226
|
-
throw new RangeError(`canonicalJson: integer outside safe range ${n}`);
|
|
12227
|
-
}
|
|
12228
|
-
return String(n);
|
|
12229
|
-
}
|
|
12230
|
-
return expandExponent(String(n));
|
|
12231
|
-
}
|
|
12232
|
-
function expandExponent(s) {
|
|
12233
|
-
if (!/[eE]/.test(s)) return s;
|
|
12234
|
-
const match = /^(-?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
|
|
12235
|
-
if (!match) {
|
|
12236
|
-
throw new TypeError(`canonicalJson: invalid number ${s}`);
|
|
12237
|
-
}
|
|
12238
|
-
const sign = match[1] ?? "";
|
|
12239
|
-
const intPart = match[2] ?? "";
|
|
12240
|
-
const fracPart = match[3] ?? "";
|
|
12241
|
-
const exp = Number(match[4]);
|
|
12242
|
-
const digits = intPart + fracPart;
|
|
12243
|
-
const point = intPart.length + exp;
|
|
12244
|
-
if (point <= 0) {
|
|
12245
|
-
return `${sign}0.${"0".repeat(-point)}${digits}`;
|
|
12246
|
-
}
|
|
12247
|
-
if (point >= digits.length) {
|
|
12248
|
-
return `${sign}${digits}${"0".repeat(point - digits.length)}`;
|
|
12249
|
-
}
|
|
12250
|
-
return `${sign}${digits.slice(0, point)}.${digits.slice(point)}`;
|
|
12251
|
-
}
|
|
12252
|
-
function serializeString(s) {
|
|
12253
|
-
let result = '"';
|
|
12254
|
-
for (let i = 0; i < s.length; i++) {
|
|
12255
|
-
const ch = s[i];
|
|
12256
|
-
const code = s.charCodeAt(i);
|
|
12257
|
-
if (ch === '"') {
|
|
12258
|
-
result += '\\"';
|
|
12259
|
-
} else if (ch === "\\") {
|
|
12260
|
-
result += "\\\\";
|
|
12261
|
-
} else if (ch === "\b") {
|
|
12262
|
-
result += "\\b";
|
|
12263
|
-
} else if (ch === "\f") {
|
|
12264
|
-
result += "\\f";
|
|
12265
|
-
} else if (ch === "\n") {
|
|
12266
|
-
result += "\\n";
|
|
12267
|
-
} else if (ch === "\r") {
|
|
12268
|
-
result += "\\r";
|
|
12269
|
-
} else if (ch === " ") {
|
|
12270
|
-
result += "\\t";
|
|
12271
|
-
} else if (code < 32) {
|
|
12272
|
-
result += "\\u" + code.toString(16).padStart(4, "0");
|
|
12273
|
-
} else {
|
|
12274
|
-
result += ch;
|
|
12275
|
-
}
|
|
12276
|
-
}
|
|
12277
|
-
result += '"';
|
|
12278
|
-
return result;
|
|
12279
|
-
}
|
|
12280
|
-
function serializeArray(arr) {
|
|
12281
|
-
const items = arr.map((item) => serialize(item));
|
|
12282
|
-
return "[" + items.join(",") + "]";
|
|
12283
|
-
}
|
|
12284
|
-
function serializeObject(obj) {
|
|
12285
|
-
const sortedKeys = Object.keys(obj).sort(compareCodePoints);
|
|
12286
|
-
const pairs = sortedKeys.map(
|
|
12287
|
-
(key) => serializeString(key) + ":" + serialize(obj[key])
|
|
12288
|
-
);
|
|
12289
|
-
return "{" + pairs.join(",") + "}";
|
|
12290
|
-
}
|
|
12291
|
-
function compareCodePoints(a, b) {
|
|
12292
|
-
const ac = Array.from(a);
|
|
12293
|
-
const bc = Array.from(b);
|
|
12294
|
-
const n = Math.min(ac.length, bc.length);
|
|
12295
|
-
for (let i = 0; i < n; i++) {
|
|
12296
|
-
const av = ac[i].codePointAt(0) ?? 0;
|
|
12297
|
-
const bv = bc[i].codePointAt(0) ?? 0;
|
|
12298
|
-
if (av !== bv) return av - bv;
|
|
12299
|
-
}
|
|
12300
|
-
return ac.length - bc.length;
|
|
12301
|
-
}
|
|
12302
|
-
|
|
12303
12934
|
// node_modules/@noble/hashes/utils.js
|
|
12304
12935
|
function isBytes(a) {
|
|
12305
12936
|
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
|
|
@@ -12368,7 +12999,7 @@ var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
|
12368
12999
|
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
12369
13000
|
))();
|
|
12370
13001
|
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
12371
|
-
function
|
|
13002
|
+
function bytesToHex2(bytes) {
|
|
12372
13003
|
abytes(bytes);
|
|
12373
13004
|
if (hasHexBuiltin)
|
|
12374
13005
|
return bytes.toHex();
|
|
@@ -12724,7 +13355,7 @@ var sha256 = /* @__PURE__ */ createHasher(
|
|
|
12724
13355
|
// node_modules/@noble/curves/utils.js
|
|
12725
13356
|
var abytes2 = (value, length, title) => abytes(value, length, title);
|
|
12726
13357
|
var anumber2 = anumber;
|
|
12727
|
-
var
|
|
13358
|
+
var bytesToHex3 = bytesToHex2;
|
|
12728
13359
|
var concatBytes2 = (...arrays) => concatBytes(...arrays);
|
|
12729
13360
|
var hexToBytes2 = (hex) => hexToBytes(hex);
|
|
12730
13361
|
var isBytes2 = isBytes;
|
|
@@ -12766,10 +13397,10 @@ function hexToNumber(hex) {
|
|
|
12766
13397
|
return hex === "" ? _0n : BigInt("0x" + hex);
|
|
12767
13398
|
}
|
|
12768
13399
|
function bytesToNumberBE(bytes) {
|
|
12769
|
-
return hexToNumber(
|
|
13400
|
+
return hexToNumber(bytesToHex2(bytes));
|
|
12770
13401
|
}
|
|
12771
13402
|
function bytesToNumberLE(bytes) {
|
|
12772
|
-
return hexToNumber(
|
|
13403
|
+
return hexToNumber(bytesToHex2(copyBytes(abytes(bytes)).reverse()));
|
|
12773
13404
|
}
|
|
12774
13405
|
function numberToBytesBE(n, len) {
|
|
12775
13406
|
anumber(len);
|
|
@@ -14155,7 +14786,7 @@ function weierstrass(params2, extraOpts = {}) {
|
|
|
14155
14786
|
return encodePoint(_Point, this, isCompressed);
|
|
14156
14787
|
}
|
|
14157
14788
|
toHex(isCompressed = true) {
|
|
14158
|
-
return
|
|
14789
|
+
return bytesToHex3(this.toBytes(isCompressed));
|
|
14159
14790
|
}
|
|
14160
14791
|
toString() {
|
|
14161
14792
|
return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
|
|
@@ -14382,7 +15013,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
14382
15013
|
return concatBytes2(rb, sb);
|
|
14383
15014
|
}
|
|
14384
15015
|
toHex(format) {
|
|
14385
|
-
return
|
|
15016
|
+
return bytesToHex3(this.toBytes(format));
|
|
14386
15017
|
}
|
|
14387
15018
|
}
|
|
14388
15019
|
Object.freeze(Signature.prototype);
|
|
@@ -14749,7 +15380,7 @@ async function sha2562(data) {
|
|
|
14749
15380
|
const buf = await crypto.subtle.digest("SHA-256", data.slice().buffer);
|
|
14750
15381
|
return new Uint8Array(buf);
|
|
14751
15382
|
}
|
|
14752
|
-
function
|
|
15383
|
+
function bytesToHex4(b) {
|
|
14753
15384
|
let s = "";
|
|
14754
15385
|
for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, "0");
|
|
14755
15386
|
return s;
|
|
@@ -14842,7 +15473,7 @@ async function computeMerkleRoot(rows) {
|
|
|
14842
15473
|
}
|
|
14843
15474
|
layer = next;
|
|
14844
15475
|
}
|
|
14845
|
-
return
|
|
15476
|
+
return bytesToHex4(layer[0]);
|
|
14846
15477
|
}
|
|
14847
15478
|
async function verifyMerkleProof(leaf, proof, expectedRootHex) {
|
|
14848
15479
|
if (!expectedRootHex) return false;
|
|
@@ -14858,7 +15489,7 @@ async function verifyMerkleProof(leaf, proof, expectedRootHex) {
|
|
|
14858
15489
|
else if (step.position === "R") cur = await nodeHash(cur, sibling);
|
|
14859
15490
|
else return false;
|
|
14860
15491
|
}
|
|
14861
|
-
return
|
|
15492
|
+
return bytesToHex4(cur) === expectedRootHex;
|
|
14862
15493
|
}
|
|
14863
15494
|
async function computeRecipientsDigest(rows) {
|
|
14864
15495
|
return computeMerkleRoot(rows);
|
|
@@ -14968,7 +15599,7 @@ function bytesToBase643(b) {
|
|
|
14968
15599
|
for (let i = 0; i < b.length; i++) bin += String.fromCharCode(b[i]);
|
|
14969
15600
|
return btoa(bin);
|
|
14970
15601
|
}
|
|
14971
|
-
function
|
|
15602
|
+
function bytesToHex5(b) {
|
|
14972
15603
|
let s = "";
|
|
14973
15604
|
for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, "0");
|
|
14974
15605
|
return s;
|
|
@@ -14992,7 +15623,7 @@ function uuid4Hex() {
|
|
|
14992
15623
|
crypto.getRandomValues(b);
|
|
14993
15624
|
b[6] = b[6] & 15 | 64;
|
|
14994
15625
|
b[8] = b[8] & 63 | 128;
|
|
14995
|
-
return
|
|
15626
|
+
return bytesToHex5(b);
|
|
14996
15627
|
}
|
|
14997
15628
|
function randomBytes3(n) {
|
|
14998
15629
|
const b = new Uint8Array(n);
|
|
@@ -15082,7 +15713,7 @@ async function encryptP2PMessage(sender, targetSet, payload, opts = {}) {
|
|
|
15082
15713
|
pos += aadBytes.length;
|
|
15083
15714
|
signInput.set(digestBytes, pos);
|
|
15084
15715
|
const senderSig = await ecdsaSignRaw(sender.ikPriv, signInput);
|
|
15085
|
-
const certFpHash =
|
|
15716
|
+
const certFpHash = bytesToHex5(await sha2563(sender.ikPubDer));
|
|
15086
15717
|
const certFp = `sha256:${certFpHash.substring(0, 16)}`;
|
|
15087
15718
|
const envelope = {
|
|
15088
15719
|
type: "e2ee.p2p_encrypted",
|
|
@@ -15150,7 +15781,7 @@ function normalizeProtectedHeaderValue(value) {
|
|
|
15150
15781
|
async function wrapForRecipient(target, masterKey, senderSessionPriv, senderMasterPriv, wrapSalt, defaultRole) {
|
|
15151
15782
|
const role = target.role ?? defaultRole;
|
|
15152
15783
|
const keySource = target.keySource ?? "aid_master";
|
|
15153
|
-
const fpHash =
|
|
15784
|
+
const fpHash = bytesToHex5(await sha2563(target.ikPkDer));
|
|
15154
15785
|
const fp = `sha256:${fpHash.substring(0, 16)}`;
|
|
15155
15786
|
const wrapNonce = randomBytes3(12);
|
|
15156
15787
|
const use3DH = usesSPKWrap(target);
|
|
@@ -15205,7 +15836,7 @@ function bytesToBase644(b) {
|
|
|
15205
15836
|
for (let i = 0; i < b.length; i++) bin += String.fromCharCode(b[i]);
|
|
15206
15837
|
return btoa(bin);
|
|
15207
15838
|
}
|
|
15208
|
-
function
|
|
15839
|
+
function bytesToHex6(b) {
|
|
15209
15840
|
let s = "";
|
|
15210
15841
|
for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, "0");
|
|
15211
15842
|
return s;
|
|
@@ -15229,7 +15860,7 @@ function uuid4Hex2() {
|
|
|
15229
15860
|
crypto.getRandomValues(b);
|
|
15230
15861
|
b[6] = b[6] & 15 | 64;
|
|
15231
15862
|
b[8] = b[8] & 63 | 128;
|
|
15232
|
-
return
|
|
15863
|
+
return bytesToHex6(b);
|
|
15233
15864
|
}
|
|
15234
15865
|
function randomBytes4(n) {
|
|
15235
15866
|
const b = new Uint8Array(n);
|
|
@@ -15300,7 +15931,7 @@ async function encryptGroupMessage(sender, groupId, epoch, targets, payload, opt
|
|
|
15300
15931
|
pos += aadBytes.length;
|
|
15301
15932
|
signInput.set(digestBytes, pos);
|
|
15302
15933
|
const senderSig = await ecdsaSignRaw(sender.ikPriv, signInput);
|
|
15303
|
-
const certFpHash =
|
|
15934
|
+
const certFpHash = bytesToHex6(await sha2564(sender.ikPubDer));
|
|
15304
15935
|
const certFp = `sha256:${certFpHash.substring(0, 16)}`;
|
|
15305
15936
|
const envelope = {
|
|
15306
15937
|
type: "e2ee.group_encrypted",
|
|
@@ -15338,7 +15969,7 @@ async function encryptGroupMessage(sender, groupId, epoch, targets, payload, opt
|
|
|
15338
15969
|
async function wrapForRecipient2(target, masterKey, senderSessionPriv, senderMasterPriv, wrapSalt) {
|
|
15339
15970
|
const role = target.role ?? "member";
|
|
15340
15971
|
const keySource = target.keySource ?? "aid_master";
|
|
15341
|
-
const fpHash =
|
|
15972
|
+
const fpHash = bytesToHex6(await sha2564(target.ikPkDer));
|
|
15342
15973
|
const fp = `sha256:${fpHash.substring(0, 16)}`;
|
|
15343
15974
|
const wrapNonce = randomBytes4(12);
|
|
15344
15975
|
const use3DH = usesSPKWrap2(target);
|
|
@@ -15996,7 +16627,7 @@ var PEER_KEY_CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
|
15996
16627
|
var DESTROY_DELAY_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
15997
16628
|
var RECENT_GENERATIONS = 7;
|
|
15998
16629
|
var HARD_LIMIT_MS = 180 * 24 * 60 * 60 * 1e3;
|
|
15999
|
-
async function
|
|
16630
|
+
async function sha256Hex4(data) {
|
|
16000
16631
|
const buf = await crypto.subtle.digest("SHA-256", data.slice().buffer);
|
|
16001
16632
|
const arr = new Uint8Array(buf);
|
|
16002
16633
|
let hex = "";
|
|
@@ -16087,7 +16718,7 @@ var V2Session = class {
|
|
|
16087
16718
|
}
|
|
16088
16719
|
async _generateNewSPK() {
|
|
16089
16720
|
const [priv, pubDer] = await generateP256Keypair();
|
|
16090
|
-
const hex = await
|
|
16721
|
+
const hex = await sha256Hex4(pubDer);
|
|
16091
16722
|
const spkId = `sha256:${hex.substring(0, 16)}`;
|
|
16092
16723
|
await this._store.saveSPK(this._storeDeviceId, spkId, priv, pubDer);
|
|
16093
16724
|
this._spkId = spkId;
|
|
@@ -16095,7 +16726,7 @@ var V2Session = class {
|
|
|
16095
16726
|
this._spkPubDer = pubDer;
|
|
16096
16727
|
}
|
|
16097
16728
|
async _ikSPKId() {
|
|
16098
|
-
const hex = await
|
|
16729
|
+
const hex = await sha256Hex4(this._ikPubDer);
|
|
16099
16730
|
return `sha256:${hex.substring(0, 16)}`;
|
|
16100
16731
|
}
|
|
16101
16732
|
_groupKey(groupId) {
|
|
@@ -16325,7 +16956,7 @@ var V2Session = class {
|
|
|
16325
16956
|
}
|
|
16326
16957
|
}
|
|
16327
16958
|
const [priv, pubDer] = await generateP256Keypair();
|
|
16328
|
-
const hex = await
|
|
16959
|
+
const hex = await sha256Hex4(pubDer);
|
|
16329
16960
|
const spkId = `sha256:${hex.substring(0, 16)}`;
|
|
16330
16961
|
await this._store.saveGroupSPK(this._storeDeviceId, gk, spkId, priv, pubDer);
|
|
16331
16962
|
return { spkId, priv, pubDer };
|
|
@@ -16350,7 +16981,7 @@ var V2Session = class {
|
|
|
16350
16981
|
await this.ensureKeys();
|
|
16351
16982
|
const gk = this._groupKey(groupId);
|
|
16352
16983
|
const [priv, pubDer] = await generateP256Keypair();
|
|
16353
|
-
const hex = await
|
|
16984
|
+
const hex = await sha256Hex4(pubDer);
|
|
16354
16985
|
const spkId = `sha256:${hex.substring(0, 16)}`;
|
|
16355
16986
|
await this._store.saveGroupSPK(this._storeDeviceId, gk, spkId, priv, pubDer);
|
|
16356
16987
|
await this._publishGroupSPK(gk, spkId, pubDer, callFn);
|
|
@@ -16433,7 +17064,18 @@ var MEMBERSHIP_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
16433
17064
|
"invite_code_used"
|
|
16434
17065
|
]);
|
|
16435
17066
|
var JOIN_ACTIONS = /* @__PURE__ */ new Set(["member_added", "joined", "join_approved", "invite_code_used"]);
|
|
16436
|
-
function
|
|
17067
|
+
function v2PullTailDelayMs(msgCount, pageLimit) {
|
|
17068
|
+
const count = Math.trunc(Number(msgCount || 0));
|
|
17069
|
+
const limit = Math.trunc(Number(pageLimit || 0));
|
|
17070
|
+
if (count <= 0 || limit > 0 && count >= limit) return 0;
|
|
17071
|
+
return Math.min(500, Math.max(5, 1e3 / (count + 1)));
|
|
17072
|
+
}
|
|
17073
|
+
function v2Sleep(ms) {
|
|
17074
|
+
return new Promise((resolve) => {
|
|
17075
|
+
globalThis.setTimeout(resolve, ms);
|
|
17076
|
+
});
|
|
17077
|
+
}
|
|
17078
|
+
function exactArrayBuffer2(bytes) {
|
|
16437
17079
|
return bytes.slice().buffer;
|
|
16438
17080
|
}
|
|
16439
17081
|
async function pubDerMatchesFingerprint(pubDer, certFingerprint) {
|
|
@@ -16442,7 +17084,7 @@ async function pubDerMatchesFingerprint(pubDer, certFingerprint) {
|
|
|
16442
17084
|
if (!expected.startsWith("sha256:")) return false;
|
|
16443
17085
|
const expectedHex = expected.slice("sha256:".length);
|
|
16444
17086
|
if (![16, 64].includes(expectedHex.length) || !/^[0-9a-f]+$/.test(expectedHex)) return false;
|
|
16445
|
-
const digest = await crypto.subtle.digest("SHA-256",
|
|
17087
|
+
const digest = await crypto.subtle.digest("SHA-256", exactArrayBuffer2(pubDer));
|
|
16446
17088
|
const spkiHex = Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
16447
17089
|
return expectedHex.length === 16 ? spkiHex.slice(0, 16) === expectedHex : spkiHex === expectedHex;
|
|
16448
17090
|
}
|
|
@@ -16791,7 +17433,7 @@ var V2E2EECoordinator = class {
|
|
|
16791
17433
|
const pkcs8Der = v2B64ToBytes(pemBody);
|
|
16792
17434
|
const privKey = await crypto.subtle.importKey(
|
|
16793
17435
|
"pkcs8",
|
|
16794
|
-
|
|
17436
|
+
exactArrayBuffer2(pkcs8Der),
|
|
16795
17437
|
{ name: "ECDH", namedCurve: "P-256" },
|
|
16796
17438
|
true,
|
|
16797
17439
|
["deriveBits"]
|
|
@@ -17066,19 +17708,26 @@ var V2E2EECoordinator = class {
|
|
|
17066
17708
|
let nextAfterSeq = opts?.force ? afterSeq : afterSeq || (ns ? client._seqTracker.getContiguousSeq(ns) : 0);
|
|
17067
17709
|
let pageCount = 0;
|
|
17068
17710
|
let lastAutoAckSeq = 0;
|
|
17711
|
+
let pendingAckSeq = 0;
|
|
17069
17712
|
const maxPages = 100;
|
|
17070
17713
|
while (pageCount < maxPages) {
|
|
17071
17714
|
pageCount += 1;
|
|
17715
|
+
const ackUpToSeq = pendingAckSeq;
|
|
17072
17716
|
const result = await client._callRawV2Rpc("message.v2.pull", {
|
|
17073
17717
|
after_seq: nextAfterSeq,
|
|
17074
17718
|
limit,
|
|
17075
|
-
...opts?.force ? { force: true } : {}
|
|
17719
|
+
...opts?.force ? { force: true } : {},
|
|
17720
|
+
...ackUpToSeq > 0 ? { ack_up_to_seq: ackUpToSeq } : {}
|
|
17076
17721
|
});
|
|
17722
|
+
if (ackUpToSeq > 0) {
|
|
17723
|
+
pendingAckSeq = 0;
|
|
17724
|
+
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackUpToSeq);
|
|
17725
|
+
}
|
|
17077
17726
|
const pageMessages = Array.isArray(result?.messages) ? result.messages : [];
|
|
17078
17727
|
const messages = pageMessages.filter((msg) => {
|
|
17079
17728
|
const seq = Number(msg.seq ?? 0);
|
|
17080
17729
|
return Number.isFinite(seq) && seq > nextAfterSeq;
|
|
17081
|
-
});
|
|
17730
|
+
}).sort((a, b) => Number(a.seq ?? 0) - Number(b.seq ?? 0));
|
|
17082
17731
|
client._clientLog.debug(`message.v2.pull page response: page=${pageCount}, raw_count=${messages.length}, stale_count=${Math.max(0, pageMessages.length - messages.length)}, has_more=${String(result.has_more ?? "")}, server_ack_seq=${String(result.server_ack_seq ?? "")}`);
|
|
17083
17732
|
const seqs = messages.map((msg) => Number(msg.seq ?? 0)).filter((seq) => Number.isFinite(seq) && seq > 0);
|
|
17084
17733
|
const pageContigBefore = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
@@ -17151,16 +17800,33 @@ var V2E2EECoordinator = class {
|
|
|
17151
17800
|
}
|
|
17152
17801
|
const ackNeeded = pageMessages.length > 0 && ackSeq > 0 && ackSeq > lastAutoAckSeq && (contigAdvanced || hasServerAckSeq && ackSeq > serverAckSeq);
|
|
17153
17802
|
if (ackNeeded) {
|
|
17154
|
-
|
|
17155
|
-
|
|
17803
|
+
const nextAfter2 = Math.max(pageMaxSeq, nextAfterSeq);
|
|
17804
|
+
const canContinuePage2 = messages.length > 0 && nextAfter2 > nextAfterSeq;
|
|
17805
|
+
if (canContinuePage2) {
|
|
17806
|
+
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
17807
|
+
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
17808
|
+
} else {
|
|
17809
|
+
await this.ackV2(ackSeq);
|
|
17810
|
+
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
17811
|
+
}
|
|
17156
17812
|
}
|
|
17157
17813
|
}
|
|
17158
17814
|
const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
|
|
17159
|
-
|
|
17815
|
+
const rawCount = messages.length;
|
|
17816
|
+
const canContinuePage = rawCount > 0 && nextAfter > nextAfterSeq;
|
|
17817
|
+
const fullPage = canContinuePage && limit > 0 && rawCount >= limit;
|
|
17818
|
+
const shouldContinue = canContinuePage && (fullPage || pendingAckSeq > 0);
|
|
17819
|
+
if (!shouldContinue) break;
|
|
17820
|
+
const tailDelayMs = v2PullTailDelayMs(rawCount, limit);
|
|
17821
|
+
if (tailDelayMs > 0) await v2Sleep(tailDelayMs);
|
|
17160
17822
|
nextAfterSeq = nextAfter;
|
|
17161
17823
|
}
|
|
17162
17824
|
if (pageCount >= maxPages) {
|
|
17163
17825
|
client._clientLog.warn(`message.v2.pull reached max_pages=${maxPages} after_seq=${nextAfterSeq}`);
|
|
17826
|
+
if (pendingAckSeq > 0) {
|
|
17827
|
+
await this.ackV2(pendingAckSeq);
|
|
17828
|
+
pendingAckSeq = 0;
|
|
17829
|
+
}
|
|
17164
17830
|
}
|
|
17165
17831
|
return decrypted;
|
|
17166
17832
|
}
|
|
@@ -17277,17 +17943,29 @@ var V2E2EECoordinator = class {
|
|
|
17277
17943
|
const ownsCursor = opts?.ownsCursor !== false;
|
|
17278
17944
|
let nextAfterSeq = opts?.explicitAfterSeq ? afterSeq : afterSeq || client._seqTracker.getContiguousSeq(ns);
|
|
17279
17945
|
let pageCount = 0;
|
|
17946
|
+
let lastAutoAckSeq = 0;
|
|
17947
|
+
let pendingAckSeq = 0;
|
|
17280
17948
|
const maxPages = 100;
|
|
17281
17949
|
while (pageCount < maxPages) {
|
|
17282
17950
|
pageCount += 1;
|
|
17951
|
+
const ackUpToSeq = ownsCursor ? pendingAckSeq : 0;
|
|
17283
17952
|
const result = await client._callRawV2Rpc("group.v2.pull", {
|
|
17284
17953
|
group_id: wireGroupId,
|
|
17285
17954
|
group_aid: gid,
|
|
17286
17955
|
after_seq: nextAfterSeq,
|
|
17287
17956
|
limit,
|
|
17288
|
-
...cursorParams
|
|
17957
|
+
...cursorParams,
|
|
17958
|
+
...ackUpToSeq > 0 ? { ack_up_to_seq: ackUpToSeq } : {}
|
|
17289
17959
|
});
|
|
17290
|
-
|
|
17960
|
+
if (ackUpToSeq > 0) {
|
|
17961
|
+
pendingAckSeq = 0;
|
|
17962
|
+
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackUpToSeq);
|
|
17963
|
+
}
|
|
17964
|
+
const pageMessages = Array.isArray(result?.messages) ? result.messages : [];
|
|
17965
|
+
const messages = pageMessages.filter((msg) => {
|
|
17966
|
+
const seq = Number(msg.seq ?? 0);
|
|
17967
|
+
return Number.isFinite(seq) && seq > nextAfterSeq;
|
|
17968
|
+
}).sort((a, b) => Number(a.seq ?? 0) - Number(b.seq ?? 0));
|
|
17291
17969
|
const seqs = messages.map((msg) => Number(msg.seq ?? 0)).filter((seq) => Number.isFinite(seq) && seq > 0);
|
|
17292
17970
|
const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
17293
17971
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
@@ -17370,17 +18048,35 @@ var V2E2EECoordinator = class {
|
|
|
17370
18048
|
client._persistSeq(ns);
|
|
17371
18049
|
}
|
|
17372
18050
|
const hasServerCursor = cursor !== null && Object.prototype.hasOwnProperty.call(cursor, "current_seq");
|
|
17373
|
-
const ackNeeded =
|
|
18051
|
+
const ackNeeded = pageMessages.length > 0 && ackSeq > 0 && ackSeq > lastAutoAckSeq && ownsCursor && (contigAdvanced || hasServerCursor && ackSeq > cursorCurrentSeq);
|
|
17374
18052
|
if (ackNeeded) {
|
|
17375
|
-
|
|
18053
|
+
const nextAfter2 = Math.max(pageMaxSeq, nextAfterSeq);
|
|
18054
|
+
const canContinuePage2 = messages.length > 0 && nextAfter2 > nextAfterSeq && ownsCursor;
|
|
18055
|
+
if (canContinuePage2) {
|
|
18056
|
+
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
18057
|
+
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
18058
|
+
} else {
|
|
18059
|
+
await this.ackGroupV2(gid, ackSeq);
|
|
18060
|
+
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
18061
|
+
}
|
|
17376
18062
|
}
|
|
17377
18063
|
const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
|
|
17378
18064
|
if (!ownsCursor) break;
|
|
17379
|
-
|
|
18065
|
+
const rawCount = messages.length;
|
|
18066
|
+
const canContinuePage = rawCount > 0 && nextAfter > nextAfterSeq;
|
|
18067
|
+
const fullPage = canContinuePage && limit > 0 && rawCount >= limit;
|
|
18068
|
+
const shouldContinue = canContinuePage && (fullPage || pendingAckSeq > 0);
|
|
18069
|
+
if (!shouldContinue) break;
|
|
18070
|
+
const tailDelayMs = v2PullTailDelayMs(rawCount, limit);
|
|
18071
|
+
if (tailDelayMs > 0) await v2Sleep(tailDelayMs);
|
|
17380
18072
|
nextAfterSeq = nextAfter;
|
|
17381
18073
|
}
|
|
17382
18074
|
if (pageCount >= maxPages) {
|
|
17383
18075
|
client._clientLog.warn(`group.v2.pull reached max_pages=${maxPages} group=${gid} after_seq=${nextAfterSeq}`);
|
|
18076
|
+
if (pendingAckSeq > 0) {
|
|
18077
|
+
await this.ackGroupV2(gid, pendingAckSeq);
|
|
18078
|
+
pendingAckSeq = 0;
|
|
18079
|
+
}
|
|
17384
18080
|
}
|
|
17385
18081
|
return decrypted;
|
|
17386
18082
|
}
|
|
@@ -18230,7 +18926,7 @@ function lengthPrefixedBytesKey(...parts) {
|
|
|
18230
18926
|
}
|
|
18231
18927
|
return out;
|
|
18232
18928
|
}
|
|
18233
|
-
function
|
|
18929
|
+
function bytesToHex7(bytes) {
|
|
18234
18930
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
18235
18931
|
}
|
|
18236
18932
|
function sortObjectKeys(obj) {
|
|
@@ -18297,7 +18993,7 @@ async function computeStateHash(params2) {
|
|
|
18297
18993
|
offset += chunk.length;
|
|
18298
18994
|
}
|
|
18299
18995
|
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
18300
|
-
return
|
|
18996
|
+
return bytesToHex7(new Uint8Array(digest));
|
|
18301
18997
|
}
|
|
18302
18998
|
function normalizedGroupId(raw) {
|
|
18303
18999
|
const groupId = String(raw ?? "").trim();
|
|
@@ -18438,7 +19134,7 @@ var GroupStateCoordinator = class {
|
|
|
18438
19134
|
cacheData.byteOffset + cacheData.byteLength
|
|
18439
19135
|
);
|
|
18440
19136
|
const cacheHash = new Uint8Array(await crypto.subtle.digest("SHA-256", cacheInput));
|
|
18441
|
-
const cacheKey =
|
|
19137
|
+
const cacheKey = bytesToHex7(cacheHash);
|
|
18442
19138
|
const sigCache = this.runtime.groupState.sigCache;
|
|
18443
19139
|
const now = Date.now();
|
|
18444
19140
|
const cachedExp = sigCache.get(cacheKey);
|
|
@@ -19157,10 +19853,10 @@ function isAIDObject(value) {
|
|
|
19157
19853
|
candidate && typeof candidate === "object" && typeof candidate.aid === "string" && typeof candidate.aunPath === "string" && typeof candidate.isPrivateKeyValid === "function"
|
|
19158
19854
|
);
|
|
19159
19855
|
}
|
|
19160
|
-
function
|
|
19856
|
+
function bytesToHex8(bytes) {
|
|
19161
19857
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
19162
19858
|
}
|
|
19163
|
-
function
|
|
19859
|
+
function exactArrayBuffer3(bytes) {
|
|
19164
19860
|
return bytes.slice().buffer;
|
|
19165
19861
|
}
|
|
19166
19862
|
function attachGatewayProximity2(message, source) {
|
|
@@ -19173,6 +19869,13 @@ function attachGatewayProximity2(message, source) {
|
|
|
19173
19869
|
}
|
|
19174
19870
|
}
|
|
19175
19871
|
}
|
|
19872
|
+
function groupIndexBodyText(value) {
|
|
19873
|
+
if (typeof value === "string") return value;
|
|
19874
|
+
if (value && typeof value === "object" && !Array.isArray(value) && "body" in value) {
|
|
19875
|
+
return String(value.body ?? "");
|
|
19876
|
+
}
|
|
19877
|
+
return "";
|
|
19878
|
+
}
|
|
19176
19879
|
var DEFAULT_SESSION_OPTIONS = {
|
|
19177
19880
|
auto_reconnect: true,
|
|
19178
19881
|
heartbeat_interval: 30,
|
|
@@ -19525,6 +20228,8 @@ var _AUNClient = class _AUNClient {
|
|
|
19525
20228
|
__publicField(this, "_v2LazyProposeTriggered", /* @__PURE__ */ new Map());
|
|
19526
20229
|
/** agent.md 运行时管理器,负责上传、下载、缓存和 RPC 元数据观察。 */
|
|
19527
20230
|
__publicField(this, "_agentMdManager");
|
|
20231
|
+
__publicField(this, "_groupIndexMetaCache", new GroupIndexMetaCache());
|
|
20232
|
+
__publicField(this, "_groupIndexCacheLoaded", /* @__PURE__ */ new Set());
|
|
19528
20233
|
/** 消息序列号跟踪器(群消息 + P2P 空洞检测) */
|
|
19529
20234
|
__publicField(this, "_seqTracker", new SeqTracker());
|
|
19530
20235
|
__publicField(this, "_seqTrackerContext", null);
|
|
@@ -19534,9 +20239,13 @@ var _AUNClient = class _AUNClient {
|
|
|
19534
20239
|
__publicField(this, "_pushedSeqs", /* @__PURE__ */ new Map());
|
|
19535
20240
|
/** 已解密但因 seq 空洞暂缓发布的应用层消息(按 namespace -> seq) */
|
|
19536
20241
|
__publicField(this, "_pendingOrderedMsgs", /* @__PURE__ */ new Map());
|
|
20242
|
+
/** push 处理队列:按 P2P / group namespace 串行化异步解密与有序投递。 */
|
|
20243
|
+
__publicField(this, "_pushProcessQueues", /* @__PURE__ */ new Map());
|
|
19537
20244
|
/** Lazy group sync:首次发送群消息前自动拉取历史 */
|
|
19538
20245
|
__publicField(this, "_groupSynced", /* @__PURE__ */ new Set());
|
|
19539
|
-
/**
|
|
20246
|
+
/** P2P 撤回去重:原始 message_id -> 时间戳,保证应用层只回调一次 */
|
|
20247
|
+
__publicField(this, "_messageRecallSeen", /* @__PURE__ */ new Map());
|
|
20248
|
+
/** 群撤回去重:group_id|sorted(message_ids) -> 时间戳,保证应用层只回调一次 */
|
|
19540
20249
|
__publicField(this, "_groupRecallSeen", /* @__PURE__ */ new Map());
|
|
19541
20250
|
/** 在线未读 hint 队列:同一 group 只保留最后一条,延迟 drain 降低登录瞬时拉取压力。 */
|
|
19542
20251
|
__publicField(this, "_onlineUnreadHintQueue", /* @__PURE__ */ new Map());
|
|
@@ -19659,11 +20368,11 @@ var _AUNClient = class _AUNClient {
|
|
|
19659
20368
|
timeout: DEFAULT_SESSION_OPTIONS.timeouts.call,
|
|
19660
20369
|
onDisconnect: (error, closeCode) => this._handleTransportDisconnect(error, closeCode)
|
|
19661
20370
|
});
|
|
19662
|
-
this._transport.setMetaObserver(
|
|
19663
|
-
|
|
19664
|
-
this._clientLog.debug(`
|
|
19665
|
-
})
|
|
19666
|
-
|
|
20371
|
+
this._transport.setMetaObserver(
|
|
20372
|
+
(meta) => this._observeRpcMeta(meta).catch((exc) => {
|
|
20373
|
+
this._clientLog.debug(`rpc meta observer skipped: ${String(exc)}`);
|
|
20374
|
+
})
|
|
20375
|
+
);
|
|
19667
20376
|
this._runtime = new ClientRuntime(this);
|
|
19668
20377
|
this._identityRuntime = new IdentityRuntimeManager(this._runtime);
|
|
19669
20378
|
this._peerDirectory = new PeerDirectory(this._runtime);
|
|
@@ -19697,6 +20406,9 @@ var _AUNClient = class _AUNClient {
|
|
|
19697
20406
|
this._dispatcher.subscribe("_raw.message.received", (data) => {
|
|
19698
20407
|
this._onRawMessageReceived(data);
|
|
19699
20408
|
});
|
|
20409
|
+
this._dispatcher.subscribe("_raw.message.recalled", (data) => {
|
|
20410
|
+
this._safeAsync(this._onRawMessageRecalled(data));
|
|
20411
|
+
});
|
|
19700
20412
|
this._dispatcher.subscribe("_raw.group.message_created", (data) => {
|
|
19701
20413
|
this._onRawGroupMessageCreated(data);
|
|
19702
20414
|
});
|
|
@@ -19724,7 +20436,7 @@ var _AUNClient = class _AUNClient {
|
|
|
19724
20436
|
this._dispatcher.subscribe("_raw.group.state_committed", (data) => {
|
|
19725
20437
|
this._safeAsync(this._onGroupStateCommitted(data));
|
|
19726
20438
|
});
|
|
19727
|
-
for (const evt of ["message.
|
|
20439
|
+
for (const evt of ["message.ack", "storage.object_changed"]) {
|
|
19728
20440
|
this._dispatcher.subscribe(`_raw.${evt}`, (data) => {
|
|
19729
20441
|
this._dispatcher.publish(evt, data);
|
|
19730
20442
|
});
|
|
@@ -19767,7 +20479,93 @@ var _AUNClient = class _AUNClient {
|
|
|
19767
20479
|
}
|
|
19768
20480
|
/** transport 的 meta observer:吸收 gateway 注入的 _meta 字段。失败不影响业务。 */
|
|
19769
20481
|
async _observeRpcMeta(meta) {
|
|
20482
|
+
const groupIndexes = isJsonObject(meta.group_indexes) ? meta.group_indexes : {};
|
|
20483
|
+
for (const groupAid of Object.keys(groupIndexes)) {
|
|
20484
|
+
await this._loadGroupIndexCache(groupAid);
|
|
20485
|
+
}
|
|
20486
|
+
this._groupIndexMetaCache.observeRpcMeta(meta, { localAid: this._aid ?? "" });
|
|
19770
20487
|
await this._agentMdManager.observeRpcMeta(meta, this._aid);
|
|
20488
|
+
for (const groupAid of Object.keys(groupIndexes)) {
|
|
20489
|
+
await this._persistGroupIndexCache(groupAid, {
|
|
20490
|
+
remote_meta: this._groupIndexMetaCache.remoteMeta(this._aid ?? "", groupAid) ?? {},
|
|
20491
|
+
local_etag: this._groupIndexMetaCache.localEtag(this._aid ?? "", groupAid)
|
|
20492
|
+
});
|
|
20493
|
+
}
|
|
20494
|
+
}
|
|
20495
|
+
isGroupIndexStale(groupAid) {
|
|
20496
|
+
return this._groupIndexMetaCache.isStale(this._aid ?? "", groupAid);
|
|
20497
|
+
}
|
|
20498
|
+
markGroupIndexFresh(groupAid, options) {
|
|
20499
|
+
this._groupIndexMetaCache.markFresh(this._aid ?? "", groupAid, options);
|
|
20500
|
+
void this._persistGroupIndexCache(groupAid, { local_etag: String(options.etag ?? "") });
|
|
20501
|
+
}
|
|
20502
|
+
getGroupIndexRemoteMeta(groupAid) {
|
|
20503
|
+
return this._groupIndexMetaCache.remoteMeta(this._aid ?? "", groupAid);
|
|
20504
|
+
}
|
|
20505
|
+
getGroupIndexLocalEtag(groupAid) {
|
|
20506
|
+
return this._groupIndexMetaCache.localEtag(this._aid ?? "", groupAid);
|
|
20507
|
+
}
|
|
20508
|
+
async getGroupIndexCachedSettings(groupAid, keys) {
|
|
20509
|
+
await this._loadGroupIndexCache(groupAid);
|
|
20510
|
+
return this._groupIndexMetaCache.cachedSettings(this._aid ?? "", groupAid, keys.map((item) => String(item)));
|
|
20511
|
+
}
|
|
20512
|
+
async getGroupIndexCachedSettingsByEntries(groupAid, keys, entries) {
|
|
20513
|
+
await this._loadGroupIndexCache(groupAid);
|
|
20514
|
+
return this._groupIndexMetaCache.cachedSettingsByEntries(
|
|
20515
|
+
this._aid ?? "",
|
|
20516
|
+
groupAid,
|
|
20517
|
+
keys.map((item) => String(item)),
|
|
20518
|
+
entries
|
|
20519
|
+
);
|
|
20520
|
+
}
|
|
20521
|
+
cacheGroupIndexSettings(groupAid, settings, options) {
|
|
20522
|
+
this._groupIndexMetaCache.cacheSettings(this._aid ?? "", groupAid, settings, options);
|
|
20523
|
+
const entryEtags = {};
|
|
20524
|
+
for (const item of options?.entries ?? []) {
|
|
20525
|
+
const key = String(item.key ?? "");
|
|
20526
|
+
if (key) entryEtags[key] = String(item.etag ?? "");
|
|
20527
|
+
}
|
|
20528
|
+
const fields = {
|
|
20529
|
+
settings,
|
|
20530
|
+
entry_etags: entryEtags,
|
|
20531
|
+
remote_meta: this._groupIndexMetaCache.remoteMeta(this._aid ?? "", groupAid) ?? {},
|
|
20532
|
+
local_etag: String(options?.etag ?? this._groupIndexMetaCache.localEtag(this._aid ?? "", groupAid) ?? "")
|
|
20533
|
+
};
|
|
20534
|
+
const indexJsonl = groupIndexBodyText(options?.groupIndex);
|
|
20535
|
+
if (indexJsonl) fields.index_jsonl = indexJsonl;
|
|
20536
|
+
return this._persistGroupIndexCache(groupAid, fields);
|
|
20537
|
+
}
|
|
20538
|
+
_groupIndexCacheKey(groupAid) {
|
|
20539
|
+
return `${this._aid ?? ""}\0${String(groupAid ?? "")}`;
|
|
20540
|
+
}
|
|
20541
|
+
async _loadGroupIndexCache(groupAid) {
|
|
20542
|
+
const localAid = String(this._aid ?? "").trim();
|
|
20543
|
+
const group = String(groupAid ?? "").trim();
|
|
20544
|
+
if (!localAid || !group || typeof this._tokenStore.loadGroupIndexCache !== "function") return;
|
|
20545
|
+
const key = this._groupIndexCacheKey(group);
|
|
20546
|
+
if (this._groupIndexCacheLoaded.has(key)) return;
|
|
20547
|
+
this._groupIndexCacheLoaded.add(key);
|
|
20548
|
+
const record = await this._tokenStore.loadGroupIndexCache(localAid, group);
|
|
20549
|
+
if (!record) return;
|
|
20550
|
+
this._groupIndexMetaCache.restore(localAid, group, {
|
|
20551
|
+
remote_meta: record.remote_meta,
|
|
20552
|
+
local_etag: record.local_etag,
|
|
20553
|
+
settings: record.settings,
|
|
20554
|
+
entry_etags: record.entry_etags
|
|
20555
|
+
});
|
|
20556
|
+
}
|
|
20557
|
+
async _persistGroupIndexCache(groupAid, fields) {
|
|
20558
|
+
const localAid = String(this._aid ?? "").trim();
|
|
20559
|
+
const group = String(groupAid ?? "").trim();
|
|
20560
|
+
if (!localAid || !group || typeof this._tokenStore.upsertGroupIndexCache !== "function") return;
|
|
20561
|
+
const record = await this._tokenStore.upsertGroupIndexCache(localAid, group, fields);
|
|
20562
|
+
this._groupIndexCacheLoaded.add(this._groupIndexCacheKey(group));
|
|
20563
|
+
this._groupIndexMetaCache.restore(localAid, group, {
|
|
20564
|
+
remote_meta: record.remote_meta,
|
|
20565
|
+
local_etag: record.local_etag,
|
|
20566
|
+
settings: record.settings,
|
|
20567
|
+
entry_etags: record.entry_etags
|
|
20568
|
+
});
|
|
19771
20569
|
}
|
|
19772
20570
|
get state() {
|
|
19773
20571
|
return this._publicState(this._state);
|
|
@@ -19931,11 +20729,11 @@ var _AUNClient = class _AUNClient {
|
|
|
19931
20729
|
timeout: DEFAULT_SESSION_OPTIONS.timeouts.call,
|
|
19932
20730
|
onDisconnect: (error, closeCode) => this._handleTransportDisconnect(error, closeCode)
|
|
19933
20731
|
});
|
|
19934
|
-
this._transport.setMetaObserver(
|
|
19935
|
-
|
|
19936
|
-
this._clientLog.debug(`
|
|
19937
|
-
})
|
|
19938
|
-
|
|
20732
|
+
this._transport.setMetaObserver(
|
|
20733
|
+
(meta) => this._observeRpcMeta(meta).catch((exc) => {
|
|
20734
|
+
this._clientLog.debug(`rpc meta observer skipped: ${String(exc)}`);
|
|
20735
|
+
})
|
|
20736
|
+
);
|
|
19939
20737
|
this._auth.setLogger(this._logAuth);
|
|
19940
20738
|
this._transport.setLogger(this._logTransport);
|
|
19941
20739
|
this._dispatcher.setLogger(this._logEvents);
|
|
@@ -20165,8 +20963,8 @@ var _AUNClient = class _AUNClient {
|
|
|
20165
20963
|
}
|
|
20166
20964
|
const nonce = globalThis.crypto.randomUUID().replace(/-/g, "");
|
|
20167
20965
|
const issuedMs = Date.now();
|
|
20168
|
-
const oldHash =
|
|
20169
|
-
const newHash =
|
|
20966
|
+
const oldHash = bytesToHex8(new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(oldPublicKey))));
|
|
20967
|
+
const newHash = bytesToHex8(new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(newPublicKey))));
|
|
20170
20968
|
const canonical = [
|
|
20171
20969
|
"aun-group-aid-renew-v1",
|
|
20172
20970
|
groupId.toLowerCase(),
|
|
@@ -20285,7 +21083,7 @@ var _AUNClient = class _AUNClient {
|
|
|
20285
21083
|
}
|
|
20286
21084
|
const nonce = globalThis.crypto.randomUUID().replace(/-/g, "");
|
|
20287
21085
|
const issuedMs = Date.now();
|
|
20288
|
-
const publicKeyHash =
|
|
21086
|
+
const publicKeyHash = bytesToHex8(new Uint8Array(
|
|
20289
21087
|
await globalThis.crypto.subtle.digest(
|
|
20290
21088
|
"SHA-256",
|
|
20291
21089
|
new TextEncoder().encode(keyPair.public_key_der_b64)
|
|
@@ -20456,6 +21254,9 @@ var _AUNClient = class _AUNClient {
|
|
|
20456
21254
|
_onRawMessageReceived(data) {
|
|
20457
21255
|
this._delivery.onRawMessageReceived(data);
|
|
20458
21256
|
}
|
|
21257
|
+
async _onRawMessageRecalled(data) {
|
|
21258
|
+
return this._delivery.onRawMessageRecalled(data);
|
|
21259
|
+
}
|
|
20459
21260
|
/** 处理群组消息推送:re-publish(V2 加密消息走 V2 push 路径) */
|
|
20460
21261
|
_onRawGroupMessageCreated(data) {
|
|
20461
21262
|
return this._delivery.onRawGroupMessageCreated(data);
|
|
@@ -21505,7 +22306,7 @@ var _AUNClient = class _AUNClient {
|
|
|
21505
22306
|
if (!args.spkPkDer || args.spkPkDer.length === 0) {
|
|
21506
22307
|
throw new E2EEError(`spk_public_key_missing: aid=${args.aid} device_id=${args.deviceId} spk_id=${spkId}`);
|
|
21507
22308
|
}
|
|
21508
|
-
const spkHash =
|
|
22309
|
+
const spkHash = bytesToHex8(new Uint8Array(await crypto.subtle.digest("SHA-256", exactArrayBuffer3(args.spkPkDer))));
|
|
21509
22310
|
const expectedSpkId = `sha256:${spkHash.substring(0, 16)}`;
|
|
21510
22311
|
if (spkId !== expectedSpkId) {
|
|
21511
22312
|
throw new E2EEError(`spk_id_mismatch: aid=${args.aid} device_id=${args.deviceId} spk_id=${spkId} expected=${expectedSpkId}`);
|
|
@@ -22230,7 +23031,7 @@ var ServiceProxyClient = class {
|
|
|
22230
23031
|
provider_aid: this.providerAid,
|
|
22231
23032
|
services: services ?? this.listServiceSummaries()
|
|
22232
23033
|
});
|
|
22233
|
-
if (!
|
|
23034
|
+
if (!isRecord5(result)) return {};
|
|
22234
23035
|
if (result.ok === false) throw new ValidationError(String(result.error ?? "Gateway service registration failed"));
|
|
22235
23036
|
return result;
|
|
22236
23037
|
}
|
|
@@ -22243,7 +23044,7 @@ var ServiceProxyClient = class {
|
|
|
22243
23044
|
if (typeof serviceNames === "string") params2.service_names = [serviceNames];
|
|
22244
23045
|
else if (Array.isArray(serviceNames)) params2.service_names = serviceNames.map(String);
|
|
22245
23046
|
const result = await call("proxy.unregister_services", params2);
|
|
22246
|
-
return
|
|
23047
|
+
return isRecord5(result) ? result : {};
|
|
22247
23048
|
}
|
|
22248
23049
|
unregister_services_from_gateway(serviceNames) {
|
|
22249
23050
|
return this.unregisterServicesFromGateway(serviceNames);
|
|
@@ -22251,7 +23052,7 @@ var ServiceProxyClient = class {
|
|
|
22251
23052
|
async listGatewayServices() {
|
|
22252
23053
|
const call = this._gatewayCallMethod(true);
|
|
22253
23054
|
const result = await call("proxy.list_services", { provider_aid: this.providerAid });
|
|
22254
|
-
return
|
|
23055
|
+
return isRecord5(result) ? result : {};
|
|
22255
23056
|
}
|
|
22256
23057
|
list_gateway_services() {
|
|
22257
23058
|
return this.listGatewayServices();
|
|
@@ -22299,7 +23100,7 @@ var ServiceProxyClient = class {
|
|
|
22299
23100
|
});
|
|
22300
23101
|
const authResponse = parseTunnelMessage(await tunnel.recv());
|
|
22301
23102
|
if (!authResponse.ok) {
|
|
22302
|
-
const err =
|
|
23103
|
+
const err = isRecord5(authResponse.error) ? authResponse.error : {};
|
|
22303
23104
|
throw new AuthError(String(err.message ?? "Service Proxy auth failed"));
|
|
22304
23105
|
}
|
|
22305
23106
|
const registered = await this.registerServicesWithProxyServer(tunnel, {
|
|
@@ -22451,7 +23252,7 @@ var ServiceProxyClient = class {
|
|
|
22451
23252
|
return;
|
|
22452
23253
|
}
|
|
22453
23254
|
}
|
|
22454
|
-
const headers = backendHeaders(
|
|
23255
|
+
const headers = backendHeaders(isRecord5(message.headers) ? message.headers : {});
|
|
22455
23256
|
let response;
|
|
22456
23257
|
try {
|
|
22457
23258
|
const init = { method, headers };
|
|
@@ -22527,7 +23328,7 @@ var ServiceProxyClient = class {
|
|
|
22527
23328
|
backend = this._createWebSocket(
|
|
22528
23329
|
buildTargetUrl(record.endpoint, normalizePath2(String(message.path ?? "/")), String(message.query_string ?? "")),
|
|
22529
23330
|
protocols,
|
|
22530
|
-
{ headers: backendHeaders(
|
|
23331
|
+
{ headers: backendHeaders(isRecord5(message.headers) ? message.headers : {}), verifySsl: this._shouldVerifySsl() },
|
|
22531
23332
|
false
|
|
22532
23333
|
);
|
|
22533
23334
|
await waitForWsOpen(backend);
|
|
@@ -22594,7 +23395,7 @@ var ServiceProxyClient = class {
|
|
|
22594
23395
|
await this._autoRegisterServicesWithGateway();
|
|
22595
23396
|
const queue = new AsyncQueue();
|
|
22596
23397
|
const subscription = client.on("app.service_proxy.wakeup", (payload) => {
|
|
22597
|
-
if (!
|
|
23398
|
+
if (!isRecord5(payload)) return;
|
|
22598
23399
|
if (String(payload.type ?? "") !== "aun.service_proxy.wakeup") return;
|
|
22599
23400
|
const providerAid = String(payload.provider_aid ?? "").trim();
|
|
22600
23401
|
if (providerAid && providerAid !== this.providerAid) return;
|
|
@@ -22650,7 +23451,7 @@ var ServiceProxyClient = class {
|
|
|
22650
23451
|
let message;
|
|
22651
23452
|
try {
|
|
22652
23453
|
const parsed = JSON.parse(raw);
|
|
22653
|
-
if (!
|
|
23454
|
+
if (!isRecord5(parsed)) continue;
|
|
22654
23455
|
message = parsed;
|
|
22655
23456
|
} catch {
|
|
22656
23457
|
continue;
|
|
@@ -22692,7 +23493,7 @@ var ServiceProxyClient = class {
|
|
|
22692
23493
|
await tunnel.send({ type: "service_proxy_auth", request_id: authRequestId, provider_aid: this.providerAid, client_version: "js" });
|
|
22693
23494
|
const authResponse = parseTunnelMessage(await tunnel.recv());
|
|
22694
23495
|
if (!authResponse.ok) {
|
|
22695
|
-
const err =
|
|
23496
|
+
const err = isRecord5(authResponse.error) ? authResponse.error : {};
|
|
22696
23497
|
throw new AuthError(String(err.message ?? "Service Proxy auth failed"));
|
|
22697
23498
|
}
|
|
22698
23499
|
return this.registerServicesWithProxyServer(tunnel, { registerRequestId });
|
|
@@ -22710,7 +23511,7 @@ var ServiceProxyClient = class {
|
|
|
22710
23511
|
}
|
|
22711
23512
|
if (msgType !== "service_proxy_request_body") throw new Error("invalid_body_stream");
|
|
22712
23513
|
if (String(message.request_id ?? "") !== requestId) throw new Error("request body stream request_id mismatch");
|
|
22713
|
-
if (
|
|
23514
|
+
if (isRecord5(message.error)) throw new Error(String(message.error.message ?? "request body stream failed"));
|
|
22714
23515
|
const dataText = String(message.data_base64 ?? "");
|
|
22715
23516
|
if (dataText) yield decodeBase64Strict(dataText);
|
|
22716
23517
|
if (message.done === true) return;
|
|
@@ -22779,7 +23580,7 @@ var ServiceProxyClient = class {
|
|
|
22779
23580
|
_selectProxyWsUrl(payload) {
|
|
22780
23581
|
const direct = this._normalizeProxyWsUrl(String(payload.ws_url ?? ""));
|
|
22781
23582
|
if (direct) return direct;
|
|
22782
|
-
const servers = Array.isArray(payload.proxy_servers) ? payload.proxy_servers.filter(
|
|
23583
|
+
const servers = Array.isArray(payload.proxy_servers) ? payload.proxy_servers.filter(isRecord5) : [];
|
|
22783
23584
|
servers.sort((a, b) => Number(a.priority ?? 999) - Number(b.priority ?? 999));
|
|
22784
23585
|
for (const item of servers) {
|
|
22785
23586
|
const url = this._normalizeProxyWsUrl(String(item.ws_url ?? ""));
|
|
@@ -22794,7 +23595,7 @@ var ServiceProxyClient = class {
|
|
|
22794
23595
|
const response = await fetch(wellKnownUrl, { signal: controller.signal });
|
|
22795
23596
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
22796
23597
|
const payload = await response.json();
|
|
22797
|
-
if (!
|
|
23598
|
+
if (!isRecord5(payload)) throw new ValidationError("Service Proxy well-known returned invalid payload");
|
|
22798
23599
|
const wsUrl = this._selectProxyWsUrl(payload);
|
|
22799
23600
|
if (!wsUrl) throw new ValidationError("Service Proxy well-known missing valid ws_url");
|
|
22800
23601
|
return { ...payload, ws_url: wsUrl, source_url: wellKnownUrl, discovered_at: Date.now() / 1e3 };
|
|
@@ -22810,7 +23611,7 @@ var ServiceProxyClient = class {
|
|
|
22810
23611
|
if (typeof tokenStore.getMetadata === "function") raw = await tokenStore.getMetadata(this.providerAid, PROXY_DISCOVERY_CACHE_KEY);
|
|
22811
23612
|
else if (typeof tokenStore.loadMetadata === "function") raw = (await tokenStore.loadMetadata(this.providerAid))?.[PROXY_DISCOVERY_CACHE_KEY];
|
|
22812
23613
|
const cached = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
22813
|
-
if (!
|
|
23614
|
+
if (!isRecord5(cached)) return null;
|
|
22814
23615
|
const wsUrl = this._normalizeProxyWsUrl(String(cached.ws_url ?? ""));
|
|
22815
23616
|
if (!wsUrl) return null;
|
|
22816
23617
|
const discoveredAt = Number(cached.discovered_at ?? 0);
|
|
@@ -22850,7 +23651,7 @@ var ServiceProxyClient = class {
|
|
|
22850
23651
|
if (!client) return "";
|
|
22851
23652
|
const direct = this._mappingAccessToken(client);
|
|
22852
23653
|
if (direct) return direct;
|
|
22853
|
-
if (
|
|
23654
|
+
if (isRecord5(client._identity)) {
|
|
22854
23655
|
const token = this._mappingAccessToken(client._identity);
|
|
22855
23656
|
if (token) return token;
|
|
22856
23657
|
}
|
|
@@ -22883,7 +23684,7 @@ var ServiceProxyClient = class {
|
|
|
22883
23684
|
} catch (exc) {
|
|
22884
23685
|
throw new AuthError(`AUNClient authenticate failed for Service Proxy tunnel: ${formatError(exc)}`);
|
|
22885
23686
|
}
|
|
22886
|
-
const token = this._mappingAccessToken(
|
|
23687
|
+
const token = this._mappingAccessToken(isRecord5(result) ? result : null);
|
|
22887
23688
|
if (token) return token;
|
|
22888
23689
|
throw new AuthError("AUNClient authenticate did not return a valid access_token");
|
|
22889
23690
|
}
|
|
@@ -22912,7 +23713,7 @@ function isIPv4LoopbackHost(host) {
|
|
|
22912
23713
|
if (parts.length !== 4 || parts[0] !== "127") return false;
|
|
22913
23714
|
return parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) >= 0 && Number(part) <= 255);
|
|
22914
23715
|
}
|
|
22915
|
-
function
|
|
23716
|
+
function isRecord5(value) {
|
|
22916
23717
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
22917
23718
|
}
|
|
22918
23719
|
function isSensitiveMetadataKey(key) {
|
|
@@ -22923,15 +23724,15 @@ function sanitizeMetadata(metadata) {
|
|
|
22923
23724
|
const out = {};
|
|
22924
23725
|
for (const [key, value] of Object.entries(metadata ?? {})) {
|
|
22925
23726
|
if (isSensitiveMetadataKey(key)) continue;
|
|
22926
|
-
if (
|
|
22927
|
-
else if (Array.isArray(value)) out[key] = value.map((item) =>
|
|
23727
|
+
if (isRecord5(value)) out[key] = sanitizeMetadata(value);
|
|
23728
|
+
else if (Array.isArray(value)) out[key] = value.map((item) => isRecord5(item) ? sanitizeMetadata(item) : item);
|
|
22928
23729
|
else out[key] = value;
|
|
22929
23730
|
}
|
|
22930
23731
|
return out;
|
|
22931
23732
|
}
|
|
22932
23733
|
function headersMap(headers) {
|
|
22933
23734
|
const result = {};
|
|
22934
|
-
if (!
|
|
23735
|
+
if (!isRecord5(headers)) return result;
|
|
22935
23736
|
for (const [key, value] of Object.entries(headers)) result[key.toLowerCase()] = String(value);
|
|
22936
23737
|
return result;
|
|
22937
23738
|
}
|
|
@@ -22943,7 +23744,7 @@ function streamModeFrom(headers, record, message) {
|
|
|
22943
23744
|
return VALID_STREAM_MODES.has(value) ? value : "auto";
|
|
22944
23745
|
}
|
|
22945
23746
|
function detectRequestProtocol(message, record) {
|
|
22946
|
-
const headers = headersMap(
|
|
23747
|
+
const headers = headersMap(isRecord5(message.headers) ? message.headers : {});
|
|
22947
23748
|
const streamMode = streamModeFrom(headers, record, message);
|
|
22948
23749
|
let serviceType = String(message.service_type ?? "").trim().toLowerCase() || record.service_type.toLowerCase() || "http";
|
|
22949
23750
|
if (streamMode === "no_stream") {
|
|
@@ -22983,8 +23784,8 @@ function bodyHasJsonRpc(message) {
|
|
|
22983
23784
|
if (text3.includes('"jsonrpc"') || text3.includes("'jsonrpc'")) return true;
|
|
22984
23785
|
try {
|
|
22985
23786
|
const parsed = JSON.parse(text3);
|
|
22986
|
-
if (
|
|
22987
|
-
if (Array.isArray(parsed)) return parsed.some((item) =>
|
|
23787
|
+
if (isRecord5(parsed)) return String(parsed.jsonrpc ?? "") === "2.0";
|
|
23788
|
+
if (Array.isArray(parsed)) return parsed.some((item) => isRecord5(item) && String(item.jsonrpc ?? "") === "2.0");
|
|
22988
23789
|
} catch {
|
|
22989
23790
|
}
|
|
22990
23791
|
return false;
|
|
@@ -23050,7 +23851,7 @@ function streamMessage(requestId, index, status, headers, data, done) {
|
|
|
23050
23851
|
function parseTunnelMessage(raw) {
|
|
23051
23852
|
if (raw === null) throw new ConnectionError("Service Proxy tunnel closed");
|
|
23052
23853
|
const parsed = JSON.parse(raw);
|
|
23053
|
-
return
|
|
23854
|
+
return isRecord5(parsed) ? parsed : {};
|
|
23054
23855
|
}
|
|
23055
23856
|
function waitForWsOpen(ws) {
|
|
23056
23857
|
return new Promise((resolve, reject) => {
|
|
@@ -23227,10 +24028,14 @@ export {
|
|
|
23227
24028
|
EmbeddedServiceRegistry,
|
|
23228
24029
|
EndpointPolicy,
|
|
23229
24030
|
EventDispatcher,
|
|
24031
|
+
GROUP_INDEX_KEY,
|
|
24032
|
+
GROUP_INDEX_SCHEMA,
|
|
24033
|
+
GROUP_INDEX_SIG_ALG,
|
|
23230
24034
|
GatewayDiscovery,
|
|
23231
24035
|
GroupError,
|
|
23232
24036
|
GroupFSVFS,
|
|
23233
24037
|
GroupFacade,
|
|
24038
|
+
GroupIndexMetaCache,
|
|
23234
24039
|
GroupNotFoundError,
|
|
23235
24040
|
GroupStateError,
|
|
23236
24041
|
GroupThoughtFacade,
|
|
@@ -23270,6 +24075,8 @@ export {
|
|
|
23270
24075
|
ValidationError,
|
|
23271
24076
|
VERSION as __version__,
|
|
23272
24077
|
buildDiscoveryHost,
|
|
24078
|
+
buildSignedGroupIndex,
|
|
24079
|
+
computeGroupIndexBodyHash,
|
|
23273
24080
|
computeStateCommitment,
|
|
23274
24081
|
convertToGroupAid,
|
|
23275
24082
|
createConfig,
|
|
@@ -23278,18 +24085,23 @@ export {
|
|
|
23278
24085
|
encryptGroupMessage,
|
|
23279
24086
|
encryptP2PMessage,
|
|
23280
24087
|
getDeviceId,
|
|
24088
|
+
groupIndexEtag,
|
|
24089
|
+
groupIndexSigningPayload,
|
|
23281
24090
|
isGroupRemotePath,
|
|
23282
24091
|
isJsonObject,
|
|
23283
24092
|
mapCollabError,
|
|
23284
24093
|
mapRemoteError,
|
|
23285
24094
|
normalizeGroupAid,
|
|
23286
24095
|
normalizeGroupId,
|
|
24096
|
+
parseGroupIndex,
|
|
24097
|
+
prepareGroupSettingsWithIndex,
|
|
23287
24098
|
resultErr,
|
|
23288
24099
|
resultOk,
|
|
23289
24100
|
splitGroupId,
|
|
23290
24101
|
validateAIDFormat,
|
|
23291
24102
|
validateGroupAIDFormat,
|
|
23292
|
-
validateGroupIDFormat
|
|
24103
|
+
validateGroupIDFormat,
|
|
24104
|
+
verifyGroupIndex
|
|
23293
24105
|
};
|
|
23294
24106
|
/*! Bundled license information:
|
|
23295
24107
|
|