@agentunion/fastaun-browser 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bundle.js CHANGED
@@ -454,7 +454,7 @@ var init_indexeddb_store = __esm({
454
454
  });
455
455
 
456
456
  // src/version.ts
457
- var VERSION = "0.4.11";
457
+ var VERSION = "0.4.13";
458
458
 
459
459
  // src/types.ts
460
460
  var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
@@ -1838,6 +1838,31 @@ var _noopLog4 = { error: () => {
1838
1838
  }, debug: () => {
1839
1839
  } };
1840
1840
  var AUN_SDK_LANG = "javascript";
1841
+ var SENSITIVE_RPC_LOG_KEYS = /* @__PURE__ */ new Set([
1842
+ "access_token",
1843
+ "refresh_token",
1844
+ "kite_token",
1845
+ "token"
1846
+ ]);
1847
+ function redactRpcLogPayload(value, key = "", depth = 0) {
1848
+ const keyLower = key.toLowerCase();
1849
+ if (SENSITIVE_RPC_LOG_KEYS.has(keyLower) || keyLower.endsWith("_token")) {
1850
+ const text = String(value ?? "");
1851
+ return text ? `<redacted len=${text.length}>` : "";
1852
+ }
1853
+ if (depth >= 6) return "<max-depth>";
1854
+ if (Array.isArray(value)) {
1855
+ return value.map((item) => redactRpcLogPayload(item, "", depth + 1));
1856
+ }
1857
+ if (value && typeof value === "object") {
1858
+ const out = {};
1859
+ for (const [childKey, childValue] of Object.entries(value)) {
1860
+ out[childKey] = redactRpcLogPayload(childValue, childKey, depth + 1);
1861
+ }
1862
+ return out;
1863
+ }
1864
+ return value;
1865
+ }
1841
1866
  function splitPemBundle(bundle) {
1842
1867
  const marker = "-----END CERTIFICATE-----";
1843
1868
  const certs = [];
@@ -2401,6 +2426,9 @@ var _AuthFlow = class _AuthFlow {
2401
2426
  }
2402
2427
  } catch (e) {
2403
2428
  if (!(e instanceof AuthError)) throw e;
2429
+ if (this._refreshFailureRequiresRelogin(e)) {
2430
+ await this._clearCachedTokens(identity, e.message);
2431
+ }
2404
2432
  }
2405
2433
  }
2406
2434
  const login = await this.authenticate(gatewayUrl, identity.aid);
@@ -2430,14 +2458,20 @@ var _AuthFlow = class _AuthFlow {
2430
2458
  this._log.debug(`refreshCachedTokens enter: aid=${identity.aid} gateway=${gatewayUrl}`);
2431
2459
  try {
2432
2460
  const refreshToken = String(identity.refresh_token ?? "");
2433
- if (!refreshToken) throw new AuthError("missing refresh_token");
2434
- const refreshed = await this._refreshAccessToken(gatewayUrl, refreshToken);
2461
+ if (!refreshToken) {
2462
+ await this._clearCachedTokens(identity, "missing refresh_token");
2463
+ throw new AuthError("missing refresh_token");
2464
+ }
2465
+ const refreshed = await this._refreshAccessToken(gatewayUrl, refreshToken, identity);
2435
2466
  this._rememberTokens(identity, refreshed);
2436
2467
  await this._validateNewCert(identity, gatewayUrl);
2437
2468
  await this._persistIdentity(identity);
2438
2469
  this._log.debug(`refreshCachedTokens exit: elapsed=${Date.now() - tStart}ms aid=${identity.aid}`);
2439
2470
  return identity;
2440
2471
  } catch (err) {
2472
+ if (this._refreshFailureRequiresRelogin(err)) {
2473
+ await this._clearCachedTokens(identity, err instanceof Error ? err.message : String(err));
2474
+ }
2441
2475
  this._log.debug(`refreshCachedTokens exit (error): elapsed=${Date.now() - tStart}ms err=${err instanceof Error ? err.message : String(err)}`);
2442
2476
  throw err;
2443
2477
  }
@@ -2518,12 +2552,12 @@ var _AuthFlow = class _AuthFlow {
2518
2552
  method,
2519
2553
  params
2520
2554
  });
2521
- this._log.debug(`short RPC request full: ${requestPayload}`);
2555
+ this._log.debug(`short RPC request full: ${JSON.stringify(redactRpcLogPayload(JSON.parse(requestPayload)))}`);
2522
2556
  ws.send(requestPayload);
2523
2557
  return;
2524
2558
  }
2525
2559
  globalThis.clearTimeout(timeout);
2526
- this._log.debug(`short RPC response full: method=${method} ${JSON.stringify(msg)}`);
2560
+ this._log.debug(`short RPC response full: method=${method} ${JSON.stringify(redactRpcLogPayload(msg))}`);
2527
2561
  try {
2528
2562
  ws.close();
2529
2563
  } catch {
@@ -2538,7 +2572,7 @@ var _AuthFlow = class _AuthFlow {
2538
2572
  return;
2539
2573
  }
2540
2574
  if (result.success === false) {
2541
- reject(new AuthError(String(result.error ?? `${method} failed`)));
2575
+ reject(new AuthError(String(result.error ?? `${method} failed`), { data: result }));
2542
2576
  return;
2543
2577
  }
2544
2578
  resolve(result);
@@ -2674,12 +2708,28 @@ var _AuthFlow = class _AuthFlow {
2674
2708
  return phase2;
2675
2709
  }
2676
2710
  /** 刷新 access token */
2677
- async _refreshAccessToken(gatewayUrl, refreshToken) {
2678
- const result = await this._shortRpc(gatewayUrl, "auth.refresh_token", {
2679
- refresh_token: refreshToken
2680
- });
2711
+ async _refreshAccessToken(gatewayUrl, refreshToken, identity) {
2712
+ const params = {
2713
+ refresh_token: refreshToken,
2714
+ sdk_lang: AUN_SDK_LANG,
2715
+ sdk_version: VERSION
2716
+ };
2717
+ if (identity) {
2718
+ const aid = String(identity.aid ?? "").trim();
2719
+ const deviceId = String(identity.device_id ?? "").trim();
2720
+ const slotId = String(identity.slot_id ?? "").trim();
2721
+ const accessToken = String(identity.access_token ?? "").trim();
2722
+ if (aid) params.aid = aid;
2723
+ if (deviceId) params.device_id = deviceId;
2724
+ if (slotId) params.slot_id = slotId;
2725
+ if (accessToken) params.access_token = accessToken;
2726
+ if (typeof identity.access_token_expires_at === "number") {
2727
+ params.access_token_expires_at = identity.access_token_expires_at;
2728
+ }
2729
+ }
2730
+ const result = await this._shortRpc(gatewayUrl, "auth.refresh_token", params);
2681
2731
  if (!result.success) {
2682
- throw new AuthError(String(result.error ?? "refresh failed"));
2732
+ throw new AuthError(String(result.error ?? "refresh failed"), { data: result });
2683
2733
  }
2684
2734
  return result;
2685
2735
  }
@@ -3012,6 +3062,35 @@ var _AuthFlow = class _AuthFlow {
3012
3062
  const activeCert = authResult.active_cert;
3013
3063
  if (typeof activeCert === "string" && activeCert) identity._pending_active_cert = activeCert;
3014
3064
  }
3065
+ _refreshFailureRequiresRelogin(err) {
3066
+ if (!(err instanceof AuthError)) return false;
3067
+ const data = err.data;
3068
+ if (isJsonObject(data)) {
3069
+ if (data.relogin_required === true) return true;
3070
+ const error = String(data.error ?? "").trim().toLowerCase();
3071
+ return ["missing refresh_token", "invalid_or_expired_refresh_token", "refresh not supported"].includes(error);
3072
+ }
3073
+ const message = err.message.trim().toLowerCase();
3074
+ return ["missing refresh_token", "invalid_or_expired_refresh_token", "refresh not supported"].includes(message);
3075
+ }
3076
+ async _clearCachedTokens(identity, reason = "") {
3077
+ const aid = String(identity.aid ?? "");
3078
+ const hadToken = Boolean(
3079
+ identity.access_token || identity.refresh_token || identity.kite_token || identity.token || identity.access_token_expires_at
3080
+ );
3081
+ if (!hadToken) return;
3082
+ identity.access_token = "";
3083
+ identity.refresh_token = "";
3084
+ identity.kite_token = "";
3085
+ identity.token = "";
3086
+ identity.access_token_expires_at = 0;
3087
+ try {
3088
+ await this._persistIdentity(identity);
3089
+ this._log.warn(`cleared cached tokens after refresh failure: aid=${aid} reason=${reason}`);
3090
+ } catch (persistErr) {
3091
+ this._log.warn(`failed to persist token cleanup: aid=${aid} err=${persistErr instanceof Error ? persistErr.message : String(persistErr)}`);
3092
+ }
3093
+ }
3015
3094
  /** 验证服务端返回的 new_cert,通过后正式接受 */
3016
3095
  async _validateNewCert(identity, gatewayUrl = "") {
3017
3096
  const newCertPem = identity._pending_new_cert;
@@ -3710,6 +3789,52 @@ var ClientRuntime = class {
3710
3789
  var PUSHED_SEQS_LIMIT = 5e4;
3711
3790
  var PENDING_ORDERED_LIMIT = 5e4;
3712
3791
  var GROUP_RECALL_SEEN_LIMIT = 1e4;
3792
+ var APP_MESSAGE_ENVELOPE_KEYS = [
3793
+ "module_id",
3794
+ "message_type",
3795
+ "type",
3796
+ "kind",
3797
+ "version",
3798
+ "from",
3799
+ "from_aid",
3800
+ "sender_aid",
3801
+ "to",
3802
+ "to_aid",
3803
+ "group_id",
3804
+ "timestamp",
3805
+ "created_at",
3806
+ "encrypted",
3807
+ "context",
3808
+ "protected_headers",
3809
+ "headers",
3810
+ "payload_type"
3811
+ ];
3812
+ var APP_SEND_ENVELOPE_METHODS = /* @__PURE__ */ new Set([
3813
+ "message.send",
3814
+ "group.send",
3815
+ "message.thought.put",
3816
+ "group.thought.put"
3817
+ ]);
3818
+ var APP_GROUP_EVENT_ENVELOPE_KEYS = [
3819
+ "module_id",
3820
+ "event_id",
3821
+ "event_seq",
3822
+ "seq",
3823
+ "event_type",
3824
+ "action",
3825
+ "group_id",
3826
+ "actor_aid",
3827
+ "sender_aid",
3828
+ "member_aid",
3829
+ "target_aid",
3830
+ "operator_aid",
3831
+ "created_at",
3832
+ "timestamp",
3833
+ "t_server",
3834
+ "status",
3835
+ "device_id",
3836
+ "slot_id"
3837
+ ];
3713
3838
  function formatDeliveryError(error) {
3714
3839
  return error instanceof Error ? error : String(error);
3715
3840
  }
@@ -3792,8 +3917,131 @@ var MessageDeliveryEngine = class {
3792
3917
  return result;
3793
3918
  }
3794
3919
  normalizePublishedMessagePayload(event, payload) {
3795
- if (!this.isInstanceScopedMessageEvent(event)) return payload;
3796
- return this.stripInternalSenderDeviceFields(this.attachCurrentInstanceContext(payload));
3920
+ if (this.isInstanceScopedMessageEvent(event)) {
3921
+ return this.attachAppMessageEnvelope(this.stripInternalSenderDeviceFields(this.attachCurrentInstanceContext(payload)));
3922
+ }
3923
+ if (this.isGroupScopedEvent(event)) {
3924
+ return this.attachAppGroupEventEnvelope(this.attachCurrentInstanceContext(payload));
3925
+ }
3926
+ return payload;
3927
+ }
3928
+ envelopeMetadata(value) {
3929
+ let source = value;
3930
+ if (source && typeof source === "object") {
3931
+ const maybeHeaders = source;
3932
+ if (typeof maybeHeaders.toObject === "function") source = maybeHeaders.toObject();
3933
+ }
3934
+ if (!isJsonObject(source)) return void 0;
3935
+ const out = {};
3936
+ for (const [key, item] of Object.entries(source)) {
3937
+ if (key === "_auth") continue;
3938
+ out[key] = item;
3939
+ }
3940
+ return Object.keys(out).length > 0 ? out : void 0;
3941
+ }
3942
+ appMessageEnvelope(payload) {
3943
+ if (!isJsonObject(payload)) return {};
3944
+ const message = payload;
3945
+ const body = isJsonObject(message.payload) ? message.payload : {};
3946
+ const envelope = {};
3947
+ const firstValue = (...values) => {
3948
+ for (const value of values) {
3949
+ if (value === void 0 || value === null) continue;
3950
+ if (typeof value === "string" && !value.trim()) continue;
3951
+ return value;
3952
+ }
3953
+ return void 0;
3954
+ };
3955
+ const setIfPresent = (key, value) => {
3956
+ if (value === void 0 || value === null) return;
3957
+ if (typeof value === "string" && !value.trim()) return;
3958
+ envelope[key] = value;
3959
+ };
3960
+ setIfPresent("from", firstValue(message.from, message.from_aid, message.sender_aid));
3961
+ setIfPresent("to", firstValue(message.to, message.to_aid));
3962
+ setIfPresent("group_id", message.group_id);
3963
+ setIfPresent("type", firstValue(body.type, message.type, message.message_type, message.payload_type));
3964
+ setIfPresent("kind", firstValue(body.kind, message.kind));
3965
+ setIfPresent("version", firstValue(body.version, message.version));
3966
+ setIfPresent("timestamp", firstValue(message.timestamp, message.created_at, message.t_server));
3967
+ if ("encrypted" in message) envelope.encrypted = Boolean(message.encrypted);
3968
+ const context = this.envelopeMetadata(message.context);
3969
+ if (context) envelope.context = context;
3970
+ const protectedHeaders = this.envelopeMetadata(message.protected_headers) ?? this.envelopeMetadata(message.headers);
3971
+ if (protectedHeaders) envelope.protected_headers = protectedHeaders;
3972
+ setIfPresent("payload_type", firstValue(message.payload_type, protectedHeaders?.payload_type));
3973
+ return envelope;
3974
+ }
3975
+ isGroupScopedEvent(event) {
3976
+ return event === "group.changed";
3977
+ }
3978
+ appGroupEventEnvelope(payload) {
3979
+ if (!isJsonObject(payload)) return {};
3980
+ const groupEvent = payload;
3981
+ const envelope = {};
3982
+ for (const key of APP_GROUP_EVENT_ENVELOPE_KEYS) {
3983
+ if (Object.prototype.hasOwnProperty.call(groupEvent, key)) envelope[key] = groupEvent[key];
3984
+ }
3985
+ return envelope;
3986
+ }
3987
+ attachAppMessageEnvelope(payload) {
3988
+ if (!isJsonObject(payload)) return payload;
3989
+ const result = { ...payload };
3990
+ result.envelope = this.appMessageEnvelope(result);
3991
+ return result;
3992
+ }
3993
+ sendResultEnvelope(method, params, result, encrypted) {
3994
+ if (!APP_SEND_ENVELOPE_METHODS.has(method)) return {};
3995
+ const body = isJsonObject(params.payload) ? params.payload : {};
3996
+ const resultObj = isJsonObject(result) ? result : {};
3997
+ const envelope = {};
3998
+ const firstValue = (...values) => {
3999
+ for (const value of values) {
4000
+ if (value === void 0 || value === null) continue;
4001
+ if (typeof value === "string" && !value.trim()) continue;
4002
+ return value;
4003
+ }
4004
+ return void 0;
4005
+ };
4006
+ const setIfPresent = (key, value) => {
4007
+ if (value === void 0 || value === null) return;
4008
+ if (typeof value === "string" && !value.trim()) return;
4009
+ envelope[key] = value;
4010
+ };
4011
+ setIfPresent("from", this.runtime.client._aid);
4012
+ if (method.startsWith("message.")) {
4013
+ setIfPresent("to", params.to);
4014
+ } else {
4015
+ setIfPresent("group_id", params.group_id);
4016
+ }
4017
+ setIfPresent("type", firstValue(body.type, params.type, params.message_type, params.payload_type));
4018
+ setIfPresent("kind", firstValue(body.kind, params.kind));
4019
+ setIfPresent("version", firstValue(body.version, params.version));
4020
+ setIfPresent("timestamp", firstValue(params.timestamp, resultObj.timestamp, resultObj.created_at, resultObj.t_server, Date.now()));
4021
+ envelope.encrypted = Boolean(encrypted);
4022
+ const context = this.envelopeMetadata(params.context);
4023
+ if (context) envelope.context = context;
4024
+ const protectedHeaders = this.envelopeMetadata(params.protected_headers) ?? this.envelopeMetadata(params.headers);
4025
+ if (protectedHeaders) envelope.protected_headers = protectedHeaders;
4026
+ setIfPresent("payload_type", firstValue(params.payload_type, protectedHeaders?.payload_type, body.type));
4027
+ return envelope;
4028
+ }
4029
+ attachSendResultEnvelope(method, params, result, encrypted) {
4030
+ if (!APP_SEND_ENVELOPE_METHODS.has(method) || !isJsonObject(result)) return result;
4031
+ const out = { ...result };
4032
+ out.envelope = this.sendResultEnvelope(method, params, out, encrypted);
4033
+ if ("payload" in params) {
4034
+ out.payload = params.payload;
4035
+ } else if ("content" in params) {
4036
+ out.payload = params.content;
4037
+ }
4038
+ return out;
4039
+ }
4040
+ attachAppGroupEventEnvelope(payload) {
4041
+ if (!isJsonObject(payload)) return payload;
4042
+ const result = { ...payload };
4043
+ result.envelope = this.appGroupEventEnvelope(result);
4044
+ return result;
3797
4045
  }
3798
4046
  stripInternalSenderDeviceFields(payload) {
3799
4047
  if (!isJsonObject(payload)) return payload;
@@ -3813,6 +4061,11 @@ var MessageDeliveryEngine = class {
3813
4061
  const payloadType = String(payload.type ?? payload.kind ?? "").trim();
3814
4062
  if (msgType !== "message.recalled" && payloadType !== "message.recalled") return null;
3815
4063
  const event = { ...payload };
4064
+ for (const key of APP_MESSAGE_ENVELOPE_KEYS) {
4065
+ if (Object.prototype.hasOwnProperty.call(msg, key) && !(key in event)) {
4066
+ event[key] = msg[key];
4067
+ }
4068
+ }
3816
4069
  const rawIds = event.message_ids;
3817
4070
  let messageIds = Array.isArray(rawIds) ? rawIds.map((item) => String(item ?? "").trim()).filter(Boolean) : [];
3818
4071
  if (messageIds.length === 0) {
@@ -3831,7 +4084,10 @@ var MessageDeliveryEngine = class {
3831
4084
  if (!("to" in event)) event.to = msg.to ?? msg.to_aid ?? "";
3832
4085
  if (!("timestamp" in event)) event.timestamp = msg.timestamp ?? msg.t_server ?? event.recalled_at ?? 0;
3833
4086
  if ("seq" in msg && !("seq" in event)) event.seq = msg.seq;
3834
- if ("message_id" in msg && !("tombstone_message_id" in event)) event.tombstone_message_id = msg.message_id;
4087
+ if ("message_id" in msg) {
4088
+ event.message_id = msg.message_id;
4089
+ if (!("tombstone_message_id" in event)) event.tombstone_message_id = msg.message_id;
4090
+ }
3835
4091
  if ("device_id" in msg && !("device_id" in event)) event.device_id = msg.device_id;
3836
4092
  if ("slot_id" in msg && !("slot_id" in event)) event.slot_id = msg.slot_id;
3837
4093
  return event;
@@ -3850,6 +4106,11 @@ var MessageDeliveryEngine = class {
3850
4106
  const payloadType = String(payload.type ?? payload.kind ?? "").trim();
3851
4107
  if (msgType !== "group.message_recalled" && payloadType !== "group.message_recalled") return null;
3852
4108
  const event = { ...payload };
4109
+ for (const key of APP_MESSAGE_ENVELOPE_KEYS) {
4110
+ if (Object.prototype.hasOwnProperty.call(msg, key) && !(key in event)) {
4111
+ event[key] = msg[key];
4112
+ }
4113
+ }
3853
4114
  const rawIds = event.message_ids;
3854
4115
  let messageIds = Array.isArray(rawIds) ? rawIds.map((item) => String(item ?? "").trim()).filter(Boolean) : [];
3855
4116
  if (messageIds.length === 0) {
@@ -3867,7 +4128,10 @@ var MessageDeliveryEngine = class {
3867
4128
  if (!("group_id" in event)) event.group_id = msg.group_id ?? "";
3868
4129
  if (!("timestamp" in event)) event.timestamp = msg.timestamp ?? msg.t_server ?? event.recalled_at ?? 0;
3869
4130
  if ("seq" in msg) event.seq = msg.seq;
3870
- if ("message_id" in msg && !("tombstone_message_id" in event)) event.tombstone_message_id = msg.message_id;
4131
+ if ("message_id" in msg) {
4132
+ event.message_id = msg.message_id;
4133
+ if (!("tombstone_message_id" in event)) event.tombstone_message_id = msg.message_id;
4134
+ }
3871
4135
  return event;
3872
4136
  }
3873
4137
  groupRecallDedupKey(groupId, payload) {
@@ -4357,6 +4621,14 @@ var MessageDeliveryEngine = class {
4357
4621
  return;
4358
4622
  }
4359
4623
  const ns = `group_event:${groupId}`;
4624
+ if (this.isSelfJoinGroupChanged(data)) {
4625
+ const contig = client._seqTracker.getContiguousSeq(ns);
4626
+ const maxSeen = client._seqTracker.getMaxSeenSeq(ns);
4627
+ if (contig === 0 && maxSeen === 0 && eventSeq > 1) {
4628
+ client._clientLog.debug(`group.changed self-join baseline: group=${groupId}, event_seq=${eventSeq}, baseline=${eventSeq - 1}`);
4629
+ client._seqTracker.forceContiguousSeq(ns, eventSeq - 1);
4630
+ }
4631
+ }
4360
4632
  const contigBefore = client._seqTracker.getContiguousSeq(ns);
4361
4633
  if (eventSeq <= contigBefore || client._pushedSeqs.get(ns)?.has(eventSeq)) {
4362
4634
  client._clientLog.debug(`group.changed skipped duplicate/stale: group=${groupId}, event_seq=${eventSeq}, contiguous=${contigBefore}`);
@@ -4382,6 +4654,16 @@ var MessageDeliveryEngine = class {
4382
4654
  client._safeAsync(this.fillGroupEventGap(groupId));
4383
4655
  }
4384
4656
  }
4657
+ isSelfJoinGroupChanged(data) {
4658
+ const action = String(data.action ?? "").trim();
4659
+ if (!["member_added", "joined", "join_approved", "invite_code_used"].includes(action)) return false;
4660
+ const selfAid = String(this.runtime.client._aid ?? "").trim();
4661
+ if (!selfAid) return false;
4662
+ const joinedAid = String(data.joined_aid ?? data.member_aid ?? data.aid ?? "").trim();
4663
+ if (joinedAid === selfAid) return true;
4664
+ const actorAid = String(data.actor_aid ?? "").trim();
4665
+ return !joinedAid && ["joined", "invite_code_used"].includes(action) && actorAid === selfAid;
4666
+ }
4385
4667
  enqueueOnlineUnreadHint(data) {
4386
4668
  const client = this.runtime.client;
4387
4669
  const groupId = String(data.group_id ?? "").trim();
@@ -5336,6 +5618,8 @@ var RpcPipeline = class {
5336
5618
  async callImpl(method, params) {
5337
5619
  const client = this.runtime.client;
5338
5620
  const p = this.preflight(method, params).params;
5621
+ const skipSendResultEnvelope = Boolean(p._skip_send_result_envelope);
5622
+ delete p._skip_send_result_envelope;
5339
5623
  if (method === "message.send") {
5340
5624
  const encrypt = p.encrypt !== void 0 ? p.encrypt : true;
5341
5625
  delete p.encrypt;
@@ -5399,12 +5683,12 @@ var RpcPipeline = class {
5399
5683
  const pullGateKey = this.pullGateKeyForCall(method, p);
5400
5684
  if (pullGateKey) {
5401
5685
  return await this.runPullSerialized(pullGateKey, async () => {
5402
- return await this.callImplInner(method, p);
5686
+ return await this.callImplInner(method, p, skipSendResultEnvelope);
5403
5687
  });
5404
5688
  }
5405
- return await this.callImplInner(method, p);
5689
+ return await this.callImplInner(method, p, skipSendResultEnvelope);
5406
5690
  }
5407
- async callImplInner(method, p) {
5691
+ async callImplInner(method, p, skipSendResultEnvelope = false) {
5408
5692
  const client = this.runtime.client;
5409
5693
  if (method === "message.pull") {
5410
5694
  await client._ensureV2SessionReady("message.pull");
@@ -5452,6 +5736,14 @@ var RpcPipeline = class {
5452
5736
  const callTimeout = NON_IDEMPOTENT_METHODS.has(method) ? NON_IDEMPOTENT_TIMEOUT : void 0;
5453
5737
  let result = callTimeout ? await client._transport.call(method, p, callTimeout) : await client._transport.call(method, p);
5454
5738
  result = await this.postprocessResult(method, p, result);
5739
+ if (!skipSendResultEnvelope) {
5740
+ result = client._delivery.attachSendResultEnvelope(
5741
+ method,
5742
+ p,
5743
+ result,
5744
+ Boolean(p.encrypted)
5745
+ );
5746
+ }
5455
5747
  return result;
5456
5748
  }
5457
5749
  preflight(method, params) {
@@ -5482,7 +5774,8 @@ var RpcPipeline = class {
5482
5774
  if (!client._instanceProtectedHeaders || !PROTECTED_HEADERS_METHODS.has(method)) {
5483
5775
  return;
5484
5776
  }
5485
- const existing = isJsonObject(params.protected_headers) ? params.protected_headers : {};
5777
+ const existingValue = params.protected_headers ?? params.headers;
5778
+ const existing = isJsonObject(existingValue) ? existingValue : {};
5486
5779
  params.protected_headers = { ...client._instanceProtectedHeaders, ...existing };
5487
5780
  }
5488
5781
  normalizeOutboundMessagePayload(params, method = "") {
@@ -10513,17 +10806,34 @@ var V2E2EECoordinator = class {
10513
10806
  return client.call("message.send", {
10514
10807
  to: toAid,
10515
10808
  payload: envelope,
10516
- encrypt: false
10809
+ encrypt: false,
10810
+ _skip_send_result_envelope: true
10517
10811
  });
10518
10812
  };
10519
10813
  try {
10520
- return await attempt(true);
10814
+ const result = await attempt(true);
10815
+ return client._delivery.attachSendResultEnvelope("message.send", {
10816
+ to: toAid,
10817
+ payload,
10818
+ message_id: opts?.messageId,
10819
+ timestamp: opts?.timestamp,
10820
+ protected_headers: opts?.protectedHeaders,
10821
+ context: opts?.context
10822
+ }, result, true);
10521
10823
  } catch (exc) {
10522
10824
  const excCode = exc?.code;
10523
10825
  if (V2_RETRYABLE_CODES.has(excCode)) {
10524
10826
  client._clientLog.debug(`V2 P2P speculative send rejected (code=${excCode}), refreshing bootstrap`);
10525
10827
  this.deleteBootstrapCacheEntry(toAid);
10526
- return attempt(false);
10828
+ const result = await attempt(false);
10829
+ return client._delivery.attachSendResultEnvelope("message.send", {
10830
+ to: toAid,
10831
+ payload,
10832
+ message_id: opts?.messageId,
10833
+ timestamp: opts?.timestamp,
10834
+ protected_headers: opts?.protectedHeaders,
10835
+ context: opts?.context
10836
+ }, result, true);
10527
10837
  }
10528
10838
  throw exc;
10529
10839
  }
@@ -10690,7 +11000,14 @@ var V2E2EECoordinator = class {
10690
11000
  client._saveSeqTrackerState();
10691
11001
  }
10692
11002
  }
10693
- return result;
11003
+ return client._delivery.attachSendResultEnvelope("group.send", {
11004
+ group_id: gid,
11005
+ payload,
11006
+ message_id: opts?.messageId,
11007
+ timestamp: opts?.timestamp,
11008
+ protected_headers: opts?.protectedHeaders,
11009
+ context: opts?.context
11010
+ }, result, true);
10694
11011
  } catch (exc) {
10695
11012
  const excCode = exc?.code;
10696
11013
  if (V2_RETRYABLE_CODES.has(excCode)) {
@@ -10706,7 +11023,14 @@ var V2E2EECoordinator = class {
10706
11023
  client._saveSeqTrackerState();
10707
11024
  }
10708
11025
  }
10709
- return result;
11026
+ return client._delivery.attachSendResultEnvelope("group.send", {
11027
+ group_id: gid,
11028
+ payload,
11029
+ message_id: opts?.messageId,
11030
+ timestamp: opts?.timestamp,
11031
+ protected_headers: opts?.protectedHeaders,
11032
+ context: opts?.context
11033
+ }, result, true);
10710
11034
  }
10711
11035
  throw exc;
10712
11036
  }
@@ -10887,13 +11211,27 @@ var V2E2EECoordinator = class {
10887
11211
  return result;
10888
11212
  };
10889
11213
  try {
10890
- return await attempt(true);
11214
+ const result = await attempt(true);
11215
+ return client._delivery.attachSendResultEnvelope("message.thought.put", {
11216
+ ...params,
11217
+ to: toAid,
11218
+ payload,
11219
+ thought_id: thoughtId,
11220
+ timestamp
11221
+ }, result, true);
10891
11222
  } catch (exc) {
10892
11223
  const excCode = Number(exc?.code);
10893
11224
  if (V2_RETRYABLE_CODES.has(excCode)) {
10894
11225
  client._clientLog.debug(`V2 P2P thought put speculative rejected (code=${String(excCode)}), refreshing bootstrap`);
10895
11226
  this.deleteBootstrapCacheEntry(toAid);
10896
- return await attempt(false);
11227
+ const result = await attempt(false);
11228
+ return client._delivery.attachSendResultEnvelope("message.thought.put", {
11229
+ ...params,
11230
+ to: toAid,
11231
+ payload,
11232
+ thought_id: thoughtId,
11233
+ timestamp
11234
+ }, result, true);
10897
11235
  }
10898
11236
  throw exc;
10899
11237
  }
@@ -10943,13 +11281,27 @@ var V2E2EECoordinator = class {
10943
11281
  return result;
10944
11282
  };
10945
11283
  try {
10946
- return await attempt(true);
11284
+ const result = await attempt(true);
11285
+ return client._delivery.attachSendResultEnvelope("group.thought.put", {
11286
+ ...params,
11287
+ group_id: groupId,
11288
+ payload,
11289
+ thought_id: thoughtId,
11290
+ timestamp
11291
+ }, result, true);
10947
11292
  } catch (exc) {
10948
11293
  const excCode = Number(exc?.code);
10949
11294
  if (V2_RETRYABLE_CODES.has(excCode)) {
10950
11295
  client._clientLog.debug(`V2 group thought put speculative rejected (code=${String(excCode)}), refreshing bootstrap`);
10951
11296
  this.deleteBootstrapCacheEntry(`group:${groupId}`);
10952
- return await attempt(false);
11297
+ const result = await attempt(false);
11298
+ return client._delivery.attachSendResultEnvelope("group.thought.put", {
11299
+ ...params,
11300
+ group_id: groupId,
11301
+ payload,
11302
+ thought_id: thoughtId,
11303
+ timestamp
11304
+ }, result, true);
10953
11305
  }
10954
11306
  throw exc;
10955
11307
  }
@@ -15126,6 +15478,20 @@ function _v2ConcatBytes(...parts) {
15126
15478
  function formatCaughtError2(error) {
15127
15479
  return error instanceof Error ? error : String(error);
15128
15480
  }
15481
+ var RELOGIN_REFRESH_ERRORS = /* @__PURE__ */ new Set([
15482
+ "missing refresh_token",
15483
+ "invalid_or_expired_refresh_token",
15484
+ "refresh not supported"
15485
+ ]);
15486
+ function authErrorRequiresRelogin(error) {
15487
+ const data = error.data;
15488
+ if (isJsonObject(data)) {
15489
+ if (data.relogin_required === true) return true;
15490
+ const code = String(data.error ?? "").trim().toLowerCase();
15491
+ if (RELOGIN_REFRESH_ERRORS.has(code)) return true;
15492
+ }
15493
+ return RELOGIN_REFRESH_ERRORS.has(error.message.trim().toLowerCase());
15494
+ }
15129
15495
  function v2E2eeMeta2(envelope) {
15130
15496
  const suite = String(envelope.suite ?? "");
15131
15497
  const modeSuite = String(envelope.suite ?? "unknown");
@@ -16540,16 +16906,28 @@ var _AUNClient = class _AUNClient {
16540
16906
  this._tokenRefreshFailures = 0;
16541
16907
  } catch (exc) {
16542
16908
  if (exc instanceof AuthError) {
16909
+ if (authErrorRequiresRelogin(exc)) {
16910
+ this._clientLog.warn(`token refresh requires relogin, stopping refresh loop and triggering reconnect: ${exc.message}`);
16911
+ await this._dispatcher.publish("token.refresh_exhausted", {
16912
+ aid: this._identity?.aid ?? null,
16913
+ consecutive_failures: 1,
16914
+ last_error: String(exc),
16915
+ relogin_required: true
16916
+ });
16917
+ this._tokenRefreshFailures = 0;
16918
+ await this._handleTransportDisconnect(new Error("token refresh relogin required, triggering reconnect"));
16919
+ return;
16920
+ }
16543
16921
  this._tokenRefreshFailures++;
16544
16922
  if (this._tokenRefreshFailures >= 3) {
16545
- this._clientLog.warn(`token refreshconsecutivefailed ${this._tokenRefreshFailures} , stop refresh loop and trigger reconnect`);
16546
- this._dispatcher.publish("token.refresh_exhausted", {
16923
+ this._clientLog.warn(`token refresh failed ${this._tokenRefreshFailures} consecutive times, stopping refresh loop and triggering reconnect`);
16924
+ await this._dispatcher.publish("token.refresh_exhausted", {
16547
16925
  aid: this._identity?.aid ?? null,
16548
16926
  consecutive_failures: this._tokenRefreshFailures,
16549
16927
  last_error: String(exc)
16550
16928
  });
16551
16929
  this._tokenRefreshFailures = 0;
16552
- this._handleTransportDisconnect(new Error("token refresh exhausted, triggering reconnect"));
16930
+ await this._handleTransportDisconnect(new Error("token refresh exhausted, triggering reconnect"));
16553
16931
  return;
16554
16932
  }
16555
16933
  this._clientLog.warn(`token refresh failed (${this._tokenRefreshFailures}/3), next retry: ${String(exc)}`);
@@ -16684,6 +17062,21 @@ var _AUNClient = class _AUNClient {
16684
17062
  if (!this._sessionParams) {
16685
17063
  throw new StateError("missing connect params for reconnect");
16686
17064
  }
17065
+ {
17066
+ const identity = this._identity;
17067
+ if (identity) {
17068
+ const cachedToken = String(identity.access_token ?? "");
17069
+ const expiresAt = this._auth.getAccessTokenExpiry(identity);
17070
+ if (cachedToken && (expiresAt === null || expiresAt > Date.now() / 1e3 + 30)) {
17071
+ this._sessionParams.access_token = cachedToken;
17072
+ } else {
17073
+ this._clientLog.debug(`reconnect: cached token expired or missing for aid=${this._aid ?? ""}, clearing to trigger re-login`);
17074
+ this._sessionParams.access_token = "";
17075
+ }
17076
+ } else {
17077
+ this._sessionParams.access_token = "";
17078
+ }
17079
+ }
16687
17080
  await this._connectOnce(this._sessionParams, true);
16688
17081
  this._lastError = null;
16689
17082
  this._lastErrorCode = null;
@@ -19249,6 +19642,8 @@ var ServiceProxyClient = class {
19249
19642
  const stats = { connection_mode: mode, connections: 0, registered: 0, handled_requests: 0, wakeup_count: 0 };
19250
19643
  try {
19251
19644
  if (mode === "persistent") {
19645
+ const maxReconnectDelay = 6e4;
19646
+ let _delay = Math.max(0, opts.reconnectDelaySeconds ?? 1) * 1e3;
19252
19647
  while (this._running) {
19253
19648
  try {
19254
19649
  await this._autoRegisterServicesWithGateway();
@@ -19261,10 +19656,21 @@ var ServiceProxyClient = class {
19261
19656
  stats.connections = Number(stats.connections) + 1;
19262
19657
  stats.registered = Number(result.registered ?? stats.registered);
19263
19658
  stats.handled_requests = Number(stats.handled_requests) + Number(result.handled_requests ?? 0);
19659
+ _delay = Math.max(0, opts.reconnectDelaySeconds ?? 1) * 1e3;
19264
19660
  } catch (exc) {
19265
19661
  if (!this._running) break;
19266
- this._logWarn(`persistent tunnel reconnect scheduled after error: ${formatError(exc)}`);
19267
- await sleep(Math.max(0, opts.reconnectDelaySeconds ?? 1) * 1e3);
19662
+ if (exc instanceof AuthError) {
19663
+ this._logWarn(`persistent tunnel auth error, re-authenticating: ${formatError(exc)}`);
19664
+ try {
19665
+ await this._authenticateForAccessToken();
19666
+ } catch (reAuthExc) {
19667
+ this._logWarn(`re-authentication failed: ${formatError(reAuthExc)}`);
19668
+ }
19669
+ } else {
19670
+ this._logWarn(`persistent tunnel reconnect scheduled after error: ${formatError(exc)}`);
19671
+ }
19672
+ await sleep(_delay);
19673
+ _delay = Math.min(_delay * 2, maxReconnectDelay);
19268
19674
  } finally {
19269
19675
  this._activeTunnel?.close();
19270
19676
  this._activeTunnel = null;