@agentunion/fastaun-browser 0.4.2 → 0.4.4

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +190 -164
  2. package/_packed_docs/0.4.0_/345/267/256/345/274/202/346/240/270/345/256/236/345/206/263/347/255/226/350/256/260/345/275/225.md +302 -0
  3. package/_packed_docs/AUN_SDK_0.4.0_/350/256/276/350/256/241/345/257/271/346/257/224/345/210/206/346/236/220.md +194 -0
  4. package/_packed_docs/AUN_SDK_/351/207/215/346/236/204/345/256/236/346/226/275/350/256/241/345/210/222.md +596 -596
  5. package/_packed_docs/AUN_SDK_/351/207/215/346/236/204/350/256/276/350/256/241/346/226/271/346/241/210_v3.md +1698 -1697
  6. package/_packed_docs/CHANGELOG.md +190 -164
  7. package/_packed_docs/INDEX.md +17 -17
  8. package/_packed_docs/KITE_DOCS_GUIDE.md +11 -11
  9. package/_packed_docs/agent.md/SCHEMA.md +49 -49
  10. package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +22 -22
  11. 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 +327 -327
  12. package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +686 -686
  13. package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +542 -542
  14. package/_packed_docs/design/E2EE_V2/347/256/200/345/214/226/344/270/2721DH/345/212/240Per-AID_Wrap/346/226/271/346/241/210.md +124 -124
  15. package/_packed_docs/design//350/267/250/350/257/255/350/250/200/345/256/271/345/231/250E2E/346/265/213/350/257/225/346/226/271/346/241/210.md +665 -665
  16. 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 +2 -2
  17. package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +170 -170
  18. 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 +419 -419
  19. package/_packed_docs/protocol/README.md +1 -1
  20. package/_packed_docs/protocol/aun-docs-guide.md +1 -1
  21. package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +15 -15
  22. package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +4 -4
  23. package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +98 -98
  24. package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +46 -46
  25. package/_packed_docs/protocol//351/231/204/345/275/225N-/345/210/206/345/270/203/345/274/217Trace/345/215/217/350/256/256.md +257 -257
  26. package/_packed_docs/python-sdk-v2-only-changelog.md +189 -189
  27. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +7 -3
  28. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
  29. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +3 -1
  30. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
  31. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +63 -15
  32. package/_packed_docs/sdk/09-payload-reference.md +13 -13
  33. 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 +171 -171
  34. package/_packed_docs/sdk/README.md +5 -5
  35. package/dist/aid-store.d.ts.map +1 -1
  36. package/dist/aid-store.js +5 -6
  37. package/dist/aid-store.js.map +1 -1
  38. package/dist/aid.d.ts +2 -1
  39. package/dist/aid.d.ts.map +1 -1
  40. package/dist/aid.js +7 -6
  41. package/dist/aid.js.map +1 -1
  42. package/dist/auth.d.ts.map +1 -1
  43. package/dist/auth.js +4 -0
  44. package/dist/auth.js.map +1 -1
  45. package/dist/bundle.js +292 -188
  46. package/dist/client.d.ts +13 -17
  47. package/dist/client.d.ts.map +1 -1
  48. package/dist/client.js +275 -190
  49. package/dist/client.js.map +1 -1
  50. package/dist/config.d.ts +4 -7
  51. package/dist/config.d.ts.map +1 -1
  52. package/dist/config.js +18 -1
  53. package/dist/config.js.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/keystore/indexeddb.js +5 -5
  58. package/dist/keystore/indexeddb.js.map +1 -1
  59. package/dist/version.d.ts +1 -1
  60. package/dist/version.js +1 -1
  61. package/package.json +1 -1
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.2";
457
+ var VERSION = "0.4.4";
458
458
 
459
459
  // src/types.ts
460
460
  var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
@@ -708,6 +708,7 @@ function mapRemoteError(error) {
708
708
 
709
709
  // src/config.ts
710
710
  var INSTANCE_ID_PATTERN = /^[A-Za-z0-9._-]{1,128}$/;
711
+ var SLOT_ID_PATTERN = /^[A-Za-z0-9._-][A-Za-z0-9._/ :-]{0,127}$/;
711
712
  function readString(value, fallback) {
712
713
  return typeof value === "string" ? value : fallback;
713
714
  }
@@ -731,6 +732,18 @@ function normalizeInstanceId(value, field, opts = {}) {
731
732
  }
732
733
  return text;
733
734
  }
735
+ function normalizeSlotId(value, defaultValue = "default") {
736
+ const raw = String(value ?? "");
737
+ const text = raw || defaultValue;
738
+ if (!SLOT_ID_PATTERN.test(text)) {
739
+ throw new ValidationError("slot_id contains unsupported characters");
740
+ }
741
+ return text;
742
+ }
743
+ function slotIsolationKey(slotId) {
744
+ const m = slotId.match(/^[^/ :]+/);
745
+ return m ? m[0] : slotId;
746
+ }
734
747
  function getDeviceId() {
735
748
  const STORAGE_KEY = "aun_device_id";
736
749
  try {
@@ -752,7 +765,8 @@ var DEFAULTS = {
752
765
  groupE2ee: true,
753
766
  verifySsl: true,
754
767
  requireForwardSecrecy: true,
755
- replayWindowSeconds: 300
768
+ replayWindowSeconds: 300,
769
+ discoveryPort: null
756
770
  };
757
771
  function createConfig(raw) {
758
772
  const data = raw ?? {};
@@ -769,10 +783,10 @@ function createConfig(raw) {
769
783
  DEFAULTS.seedPassword
770
784
  ),
771
785
  groupE2ee: true,
772
- // 必备能力,不可配置
773
786
  verifySsl: DEFAULTS.verifySsl,
774
787
  requireForwardSecrecy: readBoolean(data.requireForwardSecrecy ?? data.require_forward_secrecy, DEFAULTS.requireForwardSecrecy),
775
- replayWindowSeconds: readOptionalNumber(data.replayWindowSeconds ?? data.replay_window_seconds, DEFAULTS.replayWindowSeconds) ?? DEFAULTS.replayWindowSeconds
788
+ replayWindowSeconds: readOptionalNumber(data.replayWindowSeconds ?? data.replay_window_seconds, DEFAULTS.replayWindowSeconds) ?? DEFAULTS.replayWindowSeconds,
789
+ discoveryPort: readOptionalNumber(data.discoveryPort ?? data.discovery_port, DEFAULTS.discoveryPort)
776
790
  };
777
791
  }
778
792
 
@@ -3128,6 +3142,9 @@ var _AuthFlow = class _AuthFlow {
3128
3142
  delete persistedRecord[key];
3129
3143
  }
3130
3144
  }
3145
+ for (const key of ["private_key_pem", "public_key_der_b64", "curve"]) {
3146
+ delete persistedRecord[key];
3147
+ }
3131
3148
  await this._keystore.saveIdentity(aid, persisted);
3132
3149
  if (Object.keys(instanceState).length === 0 || typeof this._keystore.updateInstanceState !== "function") {
3133
3150
  return;
@@ -3594,8 +3611,8 @@ function certStoreKey(aid, certFingerprint) {
3594
3611
  }
3595
3612
  function instanceStateStoreKey(aid, deviceId, slotId = "") {
3596
3613
  const normalizedDevice = normalizeInstanceId(deviceId, "device_id");
3597
- const normalizedSlot = normalizeInstanceId(slotId, "slot_id", { allowEmpty: true }) || "_singleton";
3598
- return `${safeAid(aid)}|${encodePart(normalizedDevice)}|${encodePart(normalizedSlot)}`;
3614
+ const slotKey = slotIsolationKey(slotId) || "_singleton";
3615
+ return `${safeAid(aid)}|${encodePart(normalizedDevice)}|${encodePart(slotKey)}`;
3599
3616
  }
3600
3617
  function prekeyPrefix(aid) {
3601
3618
  return `${safeAid(aid)}|`;
@@ -3629,8 +3646,8 @@ function sessionStoreKey(aid, sessionId) {
3629
3646
  }
3630
3647
  function seqTrackerPrefix(aid, deviceId, slotId) {
3631
3648
  const normalizedDevice = normalizeInstanceId(deviceId, "device_id");
3632
- const normalizedSlot = normalizeInstanceId(slotId, "slot_id", { allowEmpty: true }) || "_singleton";
3633
- return `_seq_|${safeAid(aid)}|${encodePart(normalizedDevice)}|${encodePart(normalizedSlot)}|`;
3649
+ const slotKey = slotIsolationKey(slotId) || "_singleton";
3650
+ return `_seq_|${safeAid(aid)}|${encodePart(normalizedDevice)}|${encodePart(slotKey)}|`;
3634
3651
  }
3635
3652
  function seqTrackerStoreKey(aid, deviceId, slotId, namespace) {
3636
3653
  return `${seqTrackerPrefix(aid, deviceId, slotId)}${encodePart(namespace)}`;
@@ -9689,7 +9706,8 @@ var AID = class _AID {
9689
9706
  __publicField(this, "verifySsl");
9690
9707
  __publicField(this, "rootCaPath");
9691
9708
  __publicField(this, "debug");
9692
- __publicField(this, "_privateKeyPem");
9709
+ /** AIDStore 加载时注入的明文私钥 PEM,供 AUNClient 直接使用(无需 seed)。*/
9710
+ __publicField(this, "privateKeyPem");
9693
9711
  __publicField(this, "_certValid");
9694
9712
  __publicField(this, "_privateKeyValid");
9695
9713
  __publicField(this, "_certFingerprint", "");
@@ -9707,7 +9725,7 @@ var AID = class _AID {
9707
9725
  this.certIssuer = meta.issuer;
9708
9726
  this.certNotBefore = meta.notBefore;
9709
9727
  this.certNotAfter = meta.notAfter;
9710
- this._privateKeyPem = params.privateKeyPem;
9728
+ this.privateKeyPem = params.privateKeyPem ?? "";
9711
9729
  this._certValid = params.certValid;
9712
9730
  this._privateKeyValid = params.privateKeyValid;
9713
9731
  }
@@ -9726,10 +9744,10 @@ var AID = class _AID {
9726
9744
  return this._privateKeyValid;
9727
9745
  }
9728
9746
  async sign(payload) {
9729
- if (!this._privateKeyValid || !this._privateKeyPem) return resultErr(PRIVATE_KEY_NOT_VALID, "private key is not valid");
9747
+ if (!this._privateKeyValid || !this.privateKeyPem) return resultErr(PRIVATE_KEY_NOT_VALID, "private key is not valid");
9730
9748
  try {
9731
9749
  const data = typeof payload === "string" ? new TextEncoder().encode(payload) : payload;
9732
- return resultOk({ signature: await signBytes(this._privateKeyPem, data) });
9750
+ return resultOk({ signature: await signBytes(this.privateKeyPem, data) });
9733
9751
  } catch (exc) {
9734
9752
  return resultErr(SIGNATURE_OPERATION_ERROR, String(exc), exc);
9735
9753
  }
@@ -9744,10 +9762,10 @@ var AID = class _AID {
9744
9762
  }
9745
9763
  }
9746
9764
  async signAgentMd(content) {
9747
- if (!this._privateKeyValid || !this._privateKeyPem) return resultErr(PRIVATE_KEY_NOT_VALID, "private key is not valid");
9765
+ if (!this._privateKeyValid || !this.privateKeyPem) return resultErr(PRIVATE_KEY_NOT_VALID, "private key is not valid");
9748
9766
  try {
9749
9767
  const payload = normalizeAgentMdPayload(content);
9750
- const signature = await signBytes(this._privateKeyPem, new TextEncoder().encode(payload));
9768
+ const signature = await signBytes(this.privateKeyPem, new TextEncoder().encode(payload));
9751
9769
  return resultOk({ signed: payload + buildAgentMdSignatureBlock(this.certFingerprint, Date.now() / 1e3, signature) });
9752
9770
  } catch (exc) {
9753
9771
  return resultErr(SIGNATURE_OPERATION_ERROR, String(exc), exc);
@@ -9795,6 +9813,12 @@ function getV2DeviceId(dev) {
9795
9813
  }
9796
9814
  return { present: false, value: "" };
9797
9815
  }
9816
+ function isAIDObject(value) {
9817
+ const candidate = value;
9818
+ return Boolean(
9819
+ candidate && typeof candidate === "object" && typeof candidate.aid === "string" && typeof candidate.aunPath === "string" && typeof candidate.isPrivateKeyValid === "function"
9820
+ );
9821
+ }
9798
9822
  function sortObjectKeys(obj) {
9799
9823
  if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
9800
9824
  if (Array.isArray(obj)) return obj.map(sortObjectKeys);
@@ -9927,6 +9951,20 @@ var DEFAULT_SESSION_OPTIONS = {
9927
9951
  http: 30
9928
9952
  }
9929
9953
  };
9954
+ var PUBLIC_CONNECTION_OPTION_KEYS = /* @__PURE__ */ new Set([
9955
+ "auto_reconnect",
9956
+ "connect_timeout",
9957
+ "retry_initial_delay",
9958
+ "retry_max_delay",
9959
+ "retry_max_attempts",
9960
+ "heartbeat_interval",
9961
+ "call_timeout",
9962
+ "connection_kind",
9963
+ "short_ttl_ms",
9964
+ "delivery_mode",
9965
+ "extra_info",
9966
+ "background_sync"
9967
+ ]);
9930
9968
  var PROTECTED_HEADERS_METHODS = /* @__PURE__ */ new Set([
9931
9969
  "message.send",
9932
9970
  "group.send",
@@ -10308,15 +10346,6 @@ function normalizeDeliveryModeConfig(raw, opts = {}) {
10308
10346
  affinity_ttl_ms: affinityTtlMs
10309
10347
  };
10310
10348
  }
10311
- function clientOptionsConfig(options) {
10312
- const raw = { ...options ?? {} };
10313
- if (Object.prototype.hasOwnProperty.call(raw, "aid")) {
10314
- throw new ValidationError("AUNClient options must not include aid; pass an AID object as the first argument");
10315
- }
10316
- delete raw.debug;
10317
- delete raw.protected_headers;
10318
- return raw;
10319
- }
10320
10349
  var _AUNClient = class _AUNClient {
10321
10350
  constructor(aid) {
10322
10351
  /** SDK 配置模型 */
@@ -10353,6 +10382,7 @@ var _AUNClient = class _AUNClient {
10353
10382
  // V2 E2EE 状态
10354
10383
  __publicField(this, "_v2Session");
10355
10384
  __publicField(this, "_v2KeyStore");
10385
+ __publicField(this, "_v2SessionInitInFlight", null);
10356
10386
  __publicField(this, "_v2BootstrapCache", /* @__PURE__ */ new Map());
10357
10387
  __publicField(this, "_v2SenderIKPending", /* @__PURE__ */ new Map());
10358
10388
  __publicField(this, "_v2SenderIKFetching", /* @__PURE__ */ new Set());
@@ -10428,16 +10458,15 @@ var _AUNClient = class _AUNClient {
10428
10458
  */
10429
10459
  __publicField(this, "_v2PullInflight", false);
10430
10460
  __publicField(this, "_v2PullPending", false);
10431
- const inputAid = aid instanceof AID ? aid : null;
10432
- if (typeof aid === "string") {
10433
- throw new ValidationError("AUNClient aid must be an AID object, not a string");
10461
+ if (aid !== null && aid !== void 0 && !isAIDObject(aid)) {
10462
+ throw new ValidationError("AUNClient only accepts an AID object or no argument");
10434
10463
  }
10435
- const options = {};
10436
- const rawConfig = clientOptionsConfig(options);
10464
+ const inputAid = aid ?? null;
10465
+ const rawConfig = {};
10437
10466
  if (inputAid) rawConfig.aun_path = inputAid.aunPath;
10438
- const _debug = false;
10467
+ const _debug = inputAid ? inputAid.debug : false;
10439
10468
  this.configModel = createConfig(rawConfig);
10440
- const initAid = inputAid ? inputAid.aid : null;
10469
+ const initAid = inputAid && inputAid.isPrivateKeyValid() ? inputAid.aid : null;
10441
10470
  this.config = {
10442
10471
  aun_path: this.configModel.aunPath,
10443
10472
  root_ca_path: this.configModel.rootCaPem,
@@ -10456,7 +10485,7 @@ var _AUNClient = class _AUNClient {
10456
10485
  this._clientLog.info(`AUNClient initialized: debug=${_debug} aunPath=${this.configModel.aunPath} aid=${initAid ?? "-"}`);
10457
10486
  this._dispatcher = new EventDispatcher();
10458
10487
  this._discovery = new GatewayDiscovery();
10459
- this._keystore = new IndexedDBKeyStore({ encryptionSeed: this.configModel.seedPassword ?? void 0 });
10488
+ this._keystore = new IndexedDBKeyStore({});
10460
10489
  this._slotId = inputAid?.slotId || "default";
10461
10490
  this._connectDeliveryMode = normalizeDeliveryModeConfig({ mode: "fanout" });
10462
10491
  this._defaultConnectDeliveryMode = { ...this._connectDeliveryMode };
@@ -10481,18 +10510,16 @@ var _AUNClient = class _AUNClient {
10481
10510
  });
10482
10511
  });
10483
10512
  if (inputAid) {
10484
- if (!inputAid.isPrivateKeyValid()) throw new StateError("AUNClient requires an AID with a valid private key");
10485
- this._currentAid = inputAid;
10486
- this._identity = {
10487
- aid: inputAid.aid,
10488
- private_key_pem: inputAid._privateKeyPem ?? "",
10489
- public_key_der_b64: inputAid.publicKey,
10490
- cert: inputAid.certPem
10491
- };
10492
- this._state = "disconnected";
10493
- }
10494
- if (options?.protected_headers !== void 0) {
10495
- this.setProtectedHeaders(options.protected_headers);
10513
+ if (inputAid.isPrivateKeyValid()) {
10514
+ this._currentAid = inputAid;
10515
+ this._identity = {
10516
+ aid: inputAid.aid,
10517
+ private_key_pem: inputAid.privateKeyPem,
10518
+ public_key_der_b64: inputAid.publicKey,
10519
+ cert: inputAid.certPem
10520
+ };
10521
+ this._state = "disconnected";
10522
+ }
10496
10523
  }
10497
10524
  this._auth.setLogger(this._logAuth);
10498
10525
  this._transport.setLogger(this._logTransport);
@@ -10718,7 +10745,7 @@ var _AUNClient = class _AUNClient {
10718
10745
  */
10719
10746
  async publishAgentMd(content) {
10720
10747
  const target = this._agentMdOwnerAid();
10721
- if (!target) {
10748
+ if (!target || !this._currentAid) {
10722
10749
  throw new ValidationError("publishAgentMd requires local AID");
10723
10750
  }
10724
10751
  if (content !== void 0 && content !== null) {
@@ -11213,21 +11240,78 @@ var _AUNClient = class _AUNClient {
11213
11240
  get lastErrorCode() {
11214
11241
  return this._lastErrorCode;
11215
11242
  }
11243
+ _applyAidRuntimeContext(aid) {
11244
+ const nextConfig = createConfig({
11245
+ aunPath: aid.aunPath,
11246
+ rootCaPem: aid.rootCaPath,
11247
+ verifySsl: aid.verifySsl
11248
+ });
11249
+ Object.assign(this.configModel, nextConfig);
11250
+ this.config.aun_path = nextConfig.aunPath;
11251
+ this.config.root_ca_path = nextConfig.rootCaPem;
11252
+ this.config.seed_password = nextConfig.seedPassword;
11253
+ this._agentMdPath = this._agentMdDefaultRoot();
11254
+ this._agentMdCache.clear();
11255
+ this._agentMdFetchInflight.clear();
11256
+ this._peerCache.clear();
11257
+ this._certCache.clear();
11258
+ this._gatewayUrl = null;
11259
+ this._deviceId = aid.deviceId || getDeviceId();
11260
+ this._slotId = aid.slotId || "default";
11261
+ this._logger = new AUNLogger({ debug: aid.debug, aunPath: nextConfig.aunPath });
11262
+ this._logger.bindDeviceId(this._deviceId);
11263
+ this._clientLog = this._logger.for("aun_core.client");
11264
+ this._logAuth = this._logger.for("aun_core.auth");
11265
+ this._logTransport = this._logger.for("aun_core.transport");
11266
+ this._logKeystore = this._logger.for("aun_core.keystore");
11267
+ this._logDiscovery = this._logger.for("aun_core.discovery");
11268
+ this._logEvents = this._logger.for("aun_core.events");
11269
+ this._discovery = new GatewayDiscovery();
11270
+ this._keystore = new IndexedDBKeyStore({});
11271
+ this._auth = new AuthFlow({
11272
+ keystore: this._keystore,
11273
+ crypto: new CryptoProvider(),
11274
+ aid: aid.aid,
11275
+ deviceId: this._deviceId,
11276
+ slotId: this._slotId,
11277
+ rootCaPem: nextConfig.rootCaPem,
11278
+ verifySsl: nextConfig.verifySsl
11279
+ });
11280
+ this._transport = new RPCTransport({
11281
+ eventDispatcher: this._dispatcher,
11282
+ timeout: DEFAULT_SESSION_OPTIONS.timeouts.call,
11283
+ onDisconnect: (error, closeCode) => this._handleTransportDisconnect(error, closeCode)
11284
+ });
11285
+ this._transport.setMetaObserver((meta) => {
11286
+ void this._observeRpcMeta(meta).catch((exc) => {
11287
+ this._clientLog.debug(`agent.md meta observer skipped: ${String(exc)}`);
11288
+ });
11289
+ });
11290
+ this._auth.setLogger(this._logAuth);
11291
+ this._transport.setLogger(this._logTransport);
11292
+ this._dispatcher.setLogger(this._logEvents);
11293
+ if (typeof this._discovery.setLogger === "function") {
11294
+ this._discovery.setLogger(this._logDiscovery);
11295
+ }
11296
+ if (typeof this._keystore.setLogger === "function") {
11297
+ this._keystore.setLogger(this._logKeystore);
11298
+ }
11299
+ }
11216
11300
  loadIdentity(aid) {
11217
11301
  if (!aid?.isPrivateKeyValid()) throw new StateError("loadIdentity requires an AID with a valid private key");
11218
11302
  const publicState = this.state;
11219
11303
  if (publicState !== "no_identity" /* NO_IDENTITY */ && publicState !== "closed" /* CLOSED */) {
11220
11304
  throw new StateError(`loadIdentity not allowed in state ${publicState}`);
11221
11305
  }
11306
+ this._applyAidRuntimeContext(aid);
11222
11307
  this._currentAid = aid;
11223
11308
  this._aid = aid.aid;
11224
11309
  this._identity = {
11225
11310
  aid: aid.aid,
11226
- private_key_pem: aid._privateKeyPem ?? "",
11311
+ private_key_pem: aid.privateKeyPem,
11227
11312
  public_key_der_b64: aid.publicKey,
11228
11313
  cert: aid.certPem
11229
11314
  };
11230
- this._auth._aid = aid.aid;
11231
11315
  this._state = "disconnected";
11232
11316
  this._closing = false;
11233
11317
  }
@@ -11271,9 +11355,6 @@ var _AUNClient = class _AUNClient {
11271
11355
  get gatewayUrl() {
11272
11356
  return this._gatewayUrl;
11273
11357
  }
11274
- set gatewayUrl(url) {
11275
- this._gatewayUrl = url;
11276
- }
11277
11358
  get discovery() {
11278
11359
  return this._discovery;
11279
11360
  }
@@ -11314,6 +11395,17 @@ var _AUNClient = class _AUNClient {
11314
11395
  /** 连接到 Gateway;身份来自构造函数或 loadIdentity(aid),认证由 SDK 内部自动完成。 */
11315
11396
  async connect(opts) {
11316
11397
  const tStart = Date.now();
11398
+ if (opts !== void 0 && opts !== null && typeof opts === "object") {
11399
+ const raw = opts;
11400
+ const invalid = Object.keys(raw).filter((key) => !PUBLIC_CONNECTION_OPTION_KEYS.has(key)).sort();
11401
+ if (invalid.length > 0) {
11402
+ throw new ValidationError(`connect options contain unsupported field(s): ${invalid.join(", ")}`);
11403
+ }
11404
+ }
11405
+ const target = this._currentAid?.aid ?? this._aid ?? "";
11406
+ if (!target || !this._currentAid?.isPrivateKeyValid()) {
11407
+ throw new StateError("connect requires a loaded AID with a valid private key");
11408
+ }
11317
11409
  const options = {};
11318
11410
  if (opts?.auto_reconnect !== void 0) options.auto_reconnect = opts.auto_reconnect;
11319
11411
  if (opts?.heartbeat_interval !== void 0) options.heartbeat_interval = opts.heartbeat_interval;
@@ -11330,11 +11422,12 @@ var _AUNClient = class _AUNClient {
11330
11422
  max_attempts: opts.retry_max_attempts ?? 0
11331
11423
  };
11332
11424
  }
11425
+ if (opts?.connection_kind !== void 0) options.connection_kind = opts.connection_kind;
11426
+ if (opts?.short_ttl_ms !== void 0) options.short_ttl_ms = opts.short_ttl_ms;
11427
+ if (opts?.delivery_mode !== void 0) options.delivery_mode = opts.delivery_mode;
11428
+ if (opts?.extra_info !== void 0) options.extra_info = opts.extra_info;
11429
+ if (opts?.background_sync !== void 0) options.background_sync = opts.background_sync;
11333
11430
  this._clientLog.debug(`connect enter: state=${this._state} aid=${this._aid ?? "-"}`);
11334
- const target = this._currentAid?.aid ?? this._aid ?? "";
11335
- if (!target || !this._currentAid?.isPrivateKeyValid()) {
11336
- throw new StateError("connect requires a loaded AID with a valid private key");
11337
- }
11338
11431
  const publicState = this.state;
11339
11432
  const allowed = /* @__PURE__ */ new Set([
11340
11433
  "standby" /* STANDBY */,
@@ -11468,6 +11561,12 @@ var _AUNClient = class _AUNClient {
11468
11561
  }
11469
11562
  this._validateOutboundCall(method, p);
11470
11563
  this._injectMessageCursorContext(method, p);
11564
+ if (method.startsWith("group.") && !("_group_cursor_params" in p) && !Boolean(p._pull_gate_locked)) {
11565
+ const explicitCursorParams = this._groupCursorParams(p);
11566
+ if (Object.keys(explicitCursorParams).length > 0) {
11567
+ p._group_cursor_params = explicitCursorParams;
11568
+ }
11569
+ }
11471
11570
  if (method.startsWith("group.") && p.group_id !== void 0 && p.group_id !== null) {
11472
11571
  const rawGroupId = String(p.group_id);
11473
11572
  const normalizedGroupId = normalizeGroupId(rawGroupId);
@@ -11486,9 +11585,10 @@ var _AUNClient = class _AUNClient {
11486
11585
  const encrypt = p.encrypt !== void 0 ? p.encrypt : true;
11487
11586
  delete p.encrypt;
11488
11587
  if (encrypt) {
11489
- if (!this._v2Session) {
11490
- throw new StateError("V2 session not initialized; encrypted message.send requires V2 (V1 E2EE removed)");
11491
- }
11588
+ await this._ensureV2SessionReady(
11589
+ "message.send",
11590
+ "V2 session not initialized; encrypted message.send requires V2 (V1 E2EE removed)"
11591
+ );
11492
11592
  this._clientLog.debug("call route: message.send \u2192 V2 encrypted send");
11493
11593
  return await this._sendV2(String(p.to ?? ""), p.payload ?? {}, {
11494
11594
  messageId: String(p.message_id ?? "") || void 0,
@@ -11503,9 +11603,10 @@ var _AUNClient = class _AUNClient {
11503
11603
  const encrypt = p.encrypt !== void 0 ? p.encrypt : true;
11504
11604
  delete p.encrypt;
11505
11605
  if (encrypt) {
11506
- if (!this._v2Session) {
11507
- throw new StateError("V2 session not initialized; encrypted group.send requires V2 (V1 E2EE removed)");
11508
- }
11606
+ await this._ensureV2SessionReady(
11607
+ "group.send",
11608
+ "V2 session not initialized; encrypted group.send requires V2 (V1 E2EE removed)"
11609
+ );
11509
11610
  this._clientLog.debug("call route: group.send \u2192 V2 encrypted send");
11510
11611
  return await this._sendGroupV2(String(p.group_id ?? ""), p.payload ?? {}, {
11511
11612
  messageId: String(p.message_id ?? "") || void 0,
@@ -11520,9 +11621,10 @@ var _AUNClient = class _AUNClient {
11520
11621
  const encrypt = p.encrypt !== void 0 ? p.encrypt : true;
11521
11622
  delete p.encrypt;
11522
11623
  if (encrypt) {
11523
- if (!this._v2Session) {
11524
- throw new StateError("V2 session not initialized; encrypted group.thought.put requires V2 (V1 E2EE removed)");
11525
- }
11624
+ await this._ensureV2SessionReady(
11625
+ "group.thought.put",
11626
+ "V2 session not initialized; encrypted group.thought.put requires V2 (V1 E2EE removed)"
11627
+ );
11526
11628
  this._clientLog.debug("call route: group.thought.put \u2192 V2 encrypted put");
11527
11629
  return this._putGroupThoughtEncryptedV2(p);
11528
11630
  }
@@ -11531,9 +11633,10 @@ var _AUNClient = class _AUNClient {
11531
11633
  const encrypt = p.encrypt !== void 0 ? p.encrypt : true;
11532
11634
  delete p.encrypt;
11533
11635
  if (encrypt) {
11534
- if (!this._v2Session) {
11535
- throw new StateError("V2 session not initialized; encrypted message.thought.put requires V2 (V1 E2EE removed)");
11536
- }
11636
+ await this._ensureV2SessionReady(
11637
+ "message.thought.put",
11638
+ "V2 session not initialized; encrypted message.thought.put requires V2 (V1 E2EE removed)"
11639
+ );
11537
11640
  this._clientLog.debug("call route: message.thought.put \u2192 V2 encrypted put");
11538
11641
  return this._putMessageThoughtEncryptedV2(p);
11539
11642
  }
@@ -11551,26 +11654,43 @@ var _AUNClient = class _AUNClient {
11551
11654
  * 拆分出来以便 pull gate 包裹整个操作。
11552
11655
  */
11553
11656
  async _callImplInner(method, p) {
11554
- if (method === "message.pull" && this._v2Session) {
11657
+ if (method === "message.pull") {
11658
+ await this._ensureV2SessionReady("message.pull");
11555
11659
  this._clientLog.debug("call route: message.pull \u2192 V2 pull");
11556
11660
  const messages = await this._pullV2(Number(p.after_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, { force: p.force === true });
11557
11661
  return { messages };
11558
11662
  }
11559
- if (method === "message.ack" && this._v2Session) {
11663
+ if (method === "message.ack") {
11664
+ await this._ensureV2SessionReady("message.ack");
11560
11665
  this._clientLog.debug("call route: message.ack \u2192 V2 ack");
11561
11666
  return await this._ackV2(Number(p.seq ?? p.up_to_seq ?? 0) || void 0);
11562
11667
  }
11563
- if (method === "group.pull" && this._v2Session && p.group_id) {
11668
+ if (method === "group.pull" && p.group_id) {
11669
+ await this._ensureV2SessionReady("group.pull");
11564
11670
  this._clientLog.debug("call route: group.pull \u2192 V2 pull");
11671
+ const hasExplicitAfterSeq = "after_seq" in p || "after_message_seq" in p;
11672
+ const cursorParams = this._explicitGroupCursorParams(p);
11673
+ const ownsCursor = Object.keys(cursorParams).length === 0 || this._groupCursorTargetsCurrentInstance(cursorParams);
11674
+ const pullOpts = {};
11675
+ if (hasExplicitAfterSeq) pullOpts.explicitAfterSeq = true;
11676
+ if (Object.keys(cursorParams).length > 0) pullOpts.cursorParams = cursorParams;
11677
+ if (!ownsCursor) pullOpts.ownsCursor = false;
11565
11678
  const messages = await this._pullGroupV2(
11566
11679
  String(p.group_id),
11567
11680
  Number(p.after_seq ?? p.after_message_seq ?? 0) || 0,
11568
- Number(p.limit ?? 50) || 50
11681
+ Number(p.limit ?? 50) || 50,
11682
+ Object.keys(pullOpts).length > 0 ? pullOpts : void 0
11569
11683
  );
11570
11684
  return { messages };
11571
11685
  }
11572
- if (method === "group.ack_messages" && this._v2Session && p.group_id) {
11686
+ if (method === "group.ack_messages" && p.group_id) {
11687
+ await this._ensureV2SessionReady("group.ack_messages");
11573
11688
  this._clientLog.debug("call route: group.ack_messages \u2192 V2 ack");
11689
+ const cursorParams = this._explicitGroupCursorParams(p);
11690
+ const ownsCursor = Object.keys(cursorParams).length === 0 || this._groupCursorTargetsCurrentInstance(cursorParams);
11691
+ if (!ownsCursor) {
11692
+ return await this._rawGroupAckMessages(p);
11693
+ }
11574
11694
  return await this._ackGroupV2(
11575
11695
  String(p.group_id),
11576
11696
  Number(p.seq ?? p.msg_seq ?? p.up_to_seq ?? 0) || void 0
@@ -11671,6 +11791,7 @@ var _AUNClient = class _AUNClient {
11671
11791
  delete p._pull_gate_locked;
11672
11792
  delete p._skip_auto_ack;
11673
11793
  delete p.skip_auto_ack;
11794
+ delete p._group_cursor_params;
11674
11795
  if (method.startsWith("group.") && p.group_id !== void 0 && p.group_id !== null) {
11675
11796
  p.group_id = normalizeGroupId(String(p.group_id)) || String(p.group_id);
11676
11797
  }
@@ -12000,54 +12121,27 @@ var _AUNClient = class _AUNClient {
12000
12121
  /** 后台补齐群消息空洞 */
12001
12122
  async _fillGroupGap(groupId) {
12002
12123
  if (this._state !== "connected" || this._closing) return;
12124
+ groupId = normalizeGroupId(groupId) || String(groupId ?? "").trim();
12125
+ if (!groupId) return;
12003
12126
  const ns = `group:${groupId}`;
12004
12127
  const afterSeq = this._seqTracker.getContiguousSeq(ns);
12005
12128
  const dedupKey = `group_pull:${ns}`;
12006
12129
  if (this._gapFillDone.has(dedupKey)) return;
12007
12130
  this._gapFillDone.add(dedupKey);
12008
12131
  this._gapFillActive = true;
12132
+ let filled = 0;
12009
12133
  try {
12010
- const result = await this.call("group.pull", {
12011
- group_id: groupId,
12012
- after_message_seq: afterSeq,
12013
- device_id: this._deviceId,
12014
- limit: 50
12015
- });
12016
- if (isJsonObject(result)) {
12017
- const messages = result.messages;
12018
- if (Array.isArray(messages)) {
12019
- const pushed = this._pushedSeqs.get(ns);
12020
- for (const msg of messages) {
12021
- if (isJsonObject(msg)) {
12022
- const s = msg.seq;
12023
- if (pushed && s !== void 0 && s !== null && pushed.has(s)) continue;
12024
- if (s !== void 0 && s !== null) {
12025
- await this._publishPulledMessage("group.message_created", ns, s, msg);
12026
- } else {
12027
- await this._publishAppEvent("group.message_created", msg);
12028
- }
12029
- }
12030
- }
12031
- this._prunePushedSeqs(ns);
12032
- const contig = this._seqTracker.getContiguousSeq(ns);
12033
- if (contig > 0) {
12034
- const gid = groupId;
12035
- this._transport.call("group.ack_messages", {
12036
- group_id: gid,
12037
- msg_seq: contig,
12038
- device_id: this._deviceId,
12039
- slot_id: this._slotId
12040
- }).catch((e) => {
12041
- this._clientLog.warn(`group gap-fill auto-ack failed: group=${gid}`, e);
12042
- });
12043
- }
12044
- }
12045
- }
12134
+ const messages = await this._pullGroupV2(groupId, afterSeq, 50);
12135
+ filled = messages.length;
12136
+ this._prunePushedSeqs(ns);
12046
12137
  } catch (exc) {
12047
12138
  this._clientLog.warn(`group message gap-fill failed:${String(exc)}`);
12048
12139
  } finally {
12049
12140
  this._gapFillDone.delete(dedupKey);
12050
12141
  this._gapFillActive = false;
12142
+ if (filled > 0 && this._seqTracker.getContiguousSeq(ns) > afterSeq) {
12143
+ this._safeAsync(this._fillGroupGap(groupId));
12144
+ }
12051
12145
  }
12052
12146
  }
12053
12147
  /** 后台补齐群事件空洞 */
@@ -12145,44 +12239,19 @@ var _AUNClient = class _AUNClient {
12145
12239
  if (this._gapFillDone.has(dedupKey)) return;
12146
12240
  this._gapFillDone.add(dedupKey);
12147
12241
  this._gapFillActive = true;
12242
+ let filled = 0;
12148
12243
  try {
12149
- const result = await this.call("message.pull", {
12150
- after_seq: afterSeq,
12151
- limit: 50
12152
- });
12153
- if (isJsonObject(result)) {
12154
- const messages = result.messages;
12155
- if (Array.isArray(messages)) {
12156
- const pushed = this._pushedSeqs.get(ns);
12157
- for (const msg of messages) {
12158
- if (isJsonObject(msg)) {
12159
- const s = msg.seq;
12160
- if (pushed && s !== void 0 && s !== null && pushed.has(s)) continue;
12161
- if (s !== void 0 && s !== null) {
12162
- await this._publishPulledMessage("message.received", ns, s, msg);
12163
- } else {
12164
- await this._publishAppEvent("message.received", msg);
12165
- }
12166
- }
12167
- }
12168
- this._prunePushedSeqs(ns);
12169
- const contig = this._seqTracker.getContiguousSeq(ns);
12170
- if (contig > 0) {
12171
- this._transport.call("message.ack", {
12172
- seq: contig,
12173
- device_id: this._deviceId,
12174
- slot_id: this._slotId
12175
- }).catch((e) => {
12176
- this._clientLog.warn(`P2P gap-fill auto-ack failed:${String(e)}`);
12177
- });
12178
- }
12179
- }
12180
- }
12244
+ const messages = await this._pullV2(afterSeq, 50);
12245
+ filled = messages.length;
12246
+ this._prunePushedSeqs(ns);
12181
12247
  } catch (exc) {
12182
12248
  this._clientLog.warn(`P2P message gap-fill failed:${String(exc)}`);
12183
12249
  } finally {
12184
12250
  this._gapFillDone.delete(dedupKey);
12185
12251
  this._gapFillActive = false;
12252
+ if (filled > 0 && this._seqTracker.getContiguousSeq(ns) > afterSeq) {
12253
+ this._safeAsync(this._fillP2pGap());
12254
+ }
12186
12255
  }
12187
12256
  }
12188
12257
  /** 只按硬上限裁剪 published guard,不能按 contiguousSeq 清理。 */
@@ -12304,7 +12373,7 @@ var _AUNClient = class _AUNClient {
12304
12373
  }
12305
12374
  if ("slot_id" in message) {
12306
12375
  const targetSlotId = String(message.slot_id ?? "").trim();
12307
- if (targetSlotId !== this._slotId) {
12376
+ if (slotIsolationKey(targetSlotId) !== slotIsolationKey(this._slotId)) {
12308
12377
  return false;
12309
12378
  }
12310
12379
  }
@@ -13025,10 +13094,10 @@ var _AUNClient = class _AUNClient {
13025
13094
  * 使用 SubtleCrypto 异步签名。
13026
13095
  */
13027
13096
  async _signClientOperation(method, params) {
13028
- const identity = this._identity;
13029
- if (!identity || !identity.private_key_pem) return;
13097
+ const currentAid = this._currentAid;
13098
+ if (!currentAid?.privateKeyPem) return;
13030
13099
  try {
13031
- const aid = identity.aid ?? "";
13100
+ const aid = currentAid.aid;
13032
13101
  const ts = String(Math.floor(Date.now() / 1e3));
13033
13102
  const paramsForHash = {};
13034
13103
  for (const [k, v] of Object.entries(params)) {
@@ -13043,7 +13112,7 @@ var _AUNClient = class _AUNClient {
13043
13112
  );
13044
13113
  const paramsHash = Array.from(new Uint8Array(paramsHashBuf)).map((b) => b.toString(16).padStart(2, "0")).join("");
13045
13114
  const signData = new TextEncoder().encode(`${method}|${aid}|${ts}|${paramsHash}`);
13046
- const pkcs8 = pemToArrayBuffer(identity.private_key_pem);
13115
+ const pkcs8 = pemToArrayBuffer(currentAid.privateKeyPem);
13047
13116
  const cryptoKey = await crypto.subtle.importKey(
13048
13117
  "pkcs8",
13049
13118
  pkcs8,
@@ -13058,7 +13127,7 @@ var _AUNClient = class _AUNClient {
13058
13127
  );
13059
13128
  const sigDer = p1363ToDer(new Uint8Array(sigP1363));
13060
13129
  let certFingerprint = "";
13061
- const certPem = identity.cert ?? "";
13130
+ const certPem = currentAid.certPem;
13062
13131
  if (certPem) {
13063
13132
  const certDer = pemToArrayBuffer(certPem);
13064
13133
  const fpBuf = await crypto.subtle.digest("SHA-256", certDer);
@@ -13158,12 +13227,22 @@ var _AUNClient = class _AUNClient {
13158
13227
  await this._restoreSeqTrackerState();
13159
13228
  }
13160
13229
  this._startBackgroundTasks();
13161
- try {
13162
- await this._initV2Session();
13163
- } catch (exc) {
13164
- this._clientLog.warn(`V2 session init failed (non-fatal): ${String(exc)}`);
13230
+ const connectionKind = String(params.connection_kind ?? "long");
13231
+ const isShortConnection = connectionKind === "short";
13232
+ if (!isShortConnection) {
13233
+ try {
13234
+ await this._initV2Session();
13235
+ } catch (exc) {
13236
+ this._clientLog.warn(`V2 session init failed (non-fatal): ${String(exc)}`);
13237
+ }
13238
+ } else {
13239
+ this._clientLog.debug("V2 session init deferred for short connection");
13240
+ }
13241
+ const hasExplicitBackgroundSync = Object.prototype.hasOwnProperty.call(params, "background_sync");
13242
+ const backgroundSyncEnabled = this._sessionOptions?.background_sync !== false && (!isShortConnection || hasExplicitBackgroundSync);
13243
+ if (backgroundSyncEnabled) {
13244
+ this._safeAsync(this._fillP2pGap());
13165
13245
  }
13166
- this._safeAsync(this._fillP2pGap());
13167
13246
  this._clientLog.debug(`_connectOnce exit: elapsed=${Date.now() - tStart}ms aid=${this._aid ?? "-"}`);
13168
13247
  } catch (err) {
13169
13248
  this._clientLog.debug(`_connectOnce exit (error): elapsed=${Date.now() - tStart}ms err=${err instanceof Error ? err.message : String(err)}`);
@@ -13268,7 +13347,7 @@ var _AUNClient = class _AUNClient {
13268
13347
  else delete request.access_token;
13269
13348
  request.gateway = gateway;
13270
13349
  request.device_id = this._deviceId;
13271
- request.slot_id = normalizeInstanceId(request.slot_id ?? this._slotId, "slot_id", { allowEmpty: true });
13350
+ request.slot_id = normalizeSlotId(request.slot_id ?? this._slotId, this._slotId || "default");
13272
13351
  let deliveryModeRaw = request.delivery_mode;
13273
13352
  if (deliveryModeRaw == null) {
13274
13353
  deliveryModeRaw = { ...this._defaultConnectDeliveryMode };
@@ -13338,6 +13417,7 @@ var _AUNClient = class _AUNClient {
13338
13417
  if (isJsonObject(params.timeouts)) {
13339
13418
  Object.assign(options.timeouts, params.timeouts);
13340
13419
  }
13420
+ if ("background_sync" in params) options.background_sync = Boolean(params.background_sync);
13341
13421
  return options;
13342
13422
  }
13343
13423
  // ── 内部:后台任务 ────────────────────────────────
@@ -14039,6 +14119,19 @@ var _AUNClient = class _AUNClient {
14039
14119
  );
14040
14120
  return repaired;
14041
14121
  }
14122
+ async _ensureV2SessionReady(method, errorMessage) {
14123
+ if (!this._v2Session) {
14124
+ if (!this._v2SessionInitInFlight) {
14125
+ this._v2SessionInitInFlight = this._initV2Session().finally(() => {
14126
+ this._v2SessionInitInFlight = null;
14127
+ });
14128
+ }
14129
+ await this._v2SessionInitInFlight;
14130
+ }
14131
+ if (!this._v2Session) {
14132
+ throw new StateError(errorMessage ?? `V2 session not initialized; encrypted ${method} requires E2EE V2`);
14133
+ }
14134
+ }
14042
14135
  // ── V2 E2EE API(async,与 Python `client.py` `_init_v2_session` / `send_v2` / `pull_v2` / `ack_v2` 对齐) ──
14043
14136
  /**
14044
14137
  * 初始化 V2 session:从 AID PEM 私钥提取 raw scalar + DER 公钥,
@@ -14048,31 +14141,13 @@ var _AUNClient = class _AUNClient {
14048
14141
  */
14049
14142
  async _initV2Session() {
14050
14143
  if (!this._aid) return;
14051
- let identity = this._identity;
14052
- if (!identity?.private_key_pem) {
14053
- try {
14054
- const reloaded = await this._keystore.loadIdentity(this._aid);
14055
- if (reloaded?.private_key_pem) {
14056
- this._identity = reloaded;
14057
- identity = reloaded;
14058
- this._clientLog.warn("V2 session init: identity cache was stale, reloaded from keystore");
14059
- try {
14060
- const persistIdentity = this._auth._persistIdentity;
14061
- if (typeof persistIdentity === "function") {
14062
- await persistIdentity.call(this._auth, reloaded);
14063
- }
14064
- } catch {
14065
- }
14066
- }
14067
- } catch {
14068
- }
14069
- }
14070
- if (!identity?.private_key_pem) {
14144
+ const currentAid = this._currentAid;
14145
+ if (!currentAid?.privateKeyPem) {
14071
14146
  this._clientLog.warn("V2 session init skipped: no AID private key");
14072
14147
  return;
14073
14148
  }
14074
14149
  if (this._v2Session) return;
14075
- const pem = String(identity.private_key_pem).trim();
14150
+ const pem = currentAid.privateKeyPem.trim();
14076
14151
  const pemBody = pem.replace(/-----BEGIN [^-]+-----/g, "").replace(/-----END [^-]+-----/g, "").replace(/\s+/g, "");
14077
14152
  const pkcs8Der = _v2B64ToBytes(pemBody);
14078
14153
  const privKey = await crypto.subtle.importKey(
@@ -14444,6 +14519,7 @@ var _AUNClient = class _AUNClient {
14444
14519
  decrypted.push(plaintext);
14445
14520
  }
14446
14521
  }
14522
+ const hasServerAckSeq = Object.prototype.hasOwnProperty.call(result, "server_ack_seq");
14447
14523
  const serverAckSeq = Number(result.server_ack_seq ?? 0);
14448
14524
  if (ns && Number.isFinite(serverAckSeq) && serverAckSeq > 0) {
14449
14525
  const contig = this._seqTracker.getContiguousSeq(ns);
@@ -14459,7 +14535,8 @@ var _AUNClient = class _AUNClient {
14459
14535
  await this._drainOrderedMessages(ns);
14460
14536
  this._saveSeqTrackerState();
14461
14537
  }
14462
- if (messages.length > 0 && contigAdvanced && ackSeq > 0) {
14538
+ const ackNeeded = messages.length > 0 && ackSeq > 0 && (contigAdvanced || hasServerAckSeq && ackSeq > serverAckSeq);
14539
+ if (ackNeeded) {
14463
14540
  this._safeAsync(this._ackV2(ackSeq).then(() => void 0));
14464
14541
  }
14465
14542
  }
@@ -14488,7 +14565,7 @@ var _AUNClient = class _AUNClient {
14488
14565
  seq = maxSeen;
14489
14566
  }
14490
14567
  }
14491
- const raw = await this.call("message.v2.ack", { up_to_seq: seq });
14568
+ const raw = await this._callRawV2Rpc("message.v2.ack", { up_to_seq: seq });
14492
14569
  const result = isJsonObject(raw) ? { ...raw } : { result: raw };
14493
14570
  let actualAckSeq = seq;
14494
14571
  if ("effective_ack_seq" in result) actualAckSeq = Number(result.effective_ack_seq ?? 0);
@@ -14758,7 +14835,7 @@ var _AUNClient = class _AUNClient {
14758
14835
  * @param afterSeq 从此 seq 之后开始拉取(0/省略 = 从当前 contiguous 开始)
14759
14836
  * @param limit 最多拉取条数
14760
14837
  */
14761
- async _pullGroupV2(groupId, afterSeq = 0, limit = 50) {
14838
+ async _pullGroupV2(groupId, afterSeq = 0, limit = 50, opts) {
14762
14839
  if (!this._v2Session) {
14763
14840
  throw new StateError("V2 session not initialized (not connected?)");
14764
14841
  }
@@ -14766,15 +14843,18 @@ var _AUNClient = class _AUNClient {
14766
14843
  if (!gid) throw new ValidationError("group.pull requires group_id");
14767
14844
  const ns = `group:${gid}`;
14768
14845
  const decrypted = [];
14769
- let nextAfterSeq = afterSeq || this._seqTracker.getContiguousSeq(ns);
14846
+ const cursorParams = opts?.cursorParams ?? {};
14847
+ const ownsCursor = opts?.ownsCursor !== false;
14848
+ let nextAfterSeq = opts?.explicitAfterSeq ? afterSeq : afterSeq || this._seqTracker.getContiguousSeq(ns);
14770
14849
  let pageCount = 0;
14771
14850
  const maxPages = 100;
14772
14851
  while (pageCount < maxPages) {
14773
14852
  pageCount += 1;
14774
- const result = await this.call("group.v2.pull", {
14853
+ const result = await this._callRawV2Rpc("group.v2.pull", {
14775
14854
  group_id: gid,
14776
14855
  after_seq: nextAfterSeq,
14777
- limit
14856
+ limit,
14857
+ ...cursorParams
14778
14858
  });
14779
14859
  const messages = Array.isArray(result?.messages) ? result.messages : [];
14780
14860
  const seqs = messages.map((msg) => Number(msg.seq ?? 0)).filter((seq) => Number.isFinite(seq) && seq > 0);
@@ -14836,6 +14916,7 @@ var _AUNClient = class _AUNClient {
14836
14916
  decrypted.push(plaintext);
14837
14917
  }
14838
14918
  const cursor = isJsonObject(result.cursor) ? result.cursor : null;
14919
+ const hasServerCursor = cursor !== null && Object.prototype.hasOwnProperty.call(cursor, "current_seq");
14839
14920
  const serverAckSeq = Number(cursor?.current_seq ?? 0);
14840
14921
  if (Number.isFinite(serverAckSeq) && serverAckSeq > 0) {
14841
14922
  const contig = this._seqTracker.getContiguousSeq(ns);
@@ -14850,10 +14931,12 @@ var _AUNClient = class _AUNClient {
14850
14931
  await this._drainOrderedMessages(ns);
14851
14932
  this._saveSeqTrackerState();
14852
14933
  }
14853
- if (messages.length > 0 && contigAdvanced && ackSeq > 0) {
14934
+ const ackNeeded = messages.length > 0 && ackSeq > 0 && ownsCursor && (contigAdvanced || hasServerCursor && ackSeq > serverAckSeq);
14935
+ if (ackNeeded) {
14854
14936
  this._safeAsync(this._ackGroupV2(gid, ackSeq).then(() => void 0));
14855
14937
  }
14856
14938
  const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
14939
+ if (!ownsCursor) break;
14857
14940
  if (messages.length === 0 || nextAfter <= nextAfterSeq || result.has_more === false) break;
14858
14941
  nextAfterSeq = nextAfter;
14859
14942
  }
@@ -14862,6 +14945,28 @@ var _AUNClient = class _AUNClient {
14862
14945
  }
14863
14946
  return decrypted;
14864
14947
  }
14948
+ _groupCursorParams(params) {
14949
+ const cursorParams = {};
14950
+ for (const key of ["device_id", "slot_id", "device_name", "device_type"]) {
14951
+ const value = params[key];
14952
+ if (value !== void 0 && value !== null) cursorParams[key] = value;
14953
+ }
14954
+ return cursorParams;
14955
+ }
14956
+ _explicitGroupCursorParams(params) {
14957
+ const value = params._group_cursor_params;
14958
+ if (!isJsonObject(value)) return {};
14959
+ return { ...value };
14960
+ }
14961
+ _groupCursorTargetsCurrentInstance(params) {
14962
+ const deviceId = String(params.device_id ?? "").trim();
14963
+ const slotId = String(params.slot_id ?? "").trim();
14964
+ return (!deviceId || deviceId === (this._deviceId ?? "")) && (!slotId || slotId === (this._slotId ?? ""));
14965
+ }
14966
+ async _rawGroupAckMessages(params) {
14967
+ const p = { ...params };
14968
+ return await this._callRawV2Rpc("group.ack_messages", p);
14969
+ }
14865
14970
  /**
14866
14971
  * 确认 V2 群消息已消费。
14867
14972
  *
@@ -14879,7 +14984,7 @@ var _AUNClient = class _AUNClient {
14879
14984
  this._clientLog.warn(`ackGroupV2 clamp: group=${gid} up_to_seq=${seq} > max_seen=${maxSeen}, clamp`);
14880
14985
  seq = maxSeen;
14881
14986
  }
14882
- return this.call("group.v2.ack", { group_id: gid, up_to_seq: seq });
14987
+ return this._callRawV2Rpc("group.v2.ack", { group_id: gid, up_to_seq: seq });
14883
14988
  }
14884
14989
  // ── V2 thought(per-device wrap,服务端透传,不持久化)──────────
14885
14990
  /**
@@ -15638,8 +15743,8 @@ var _AUNClient = class _AUNClient {
15638
15743
  return;
15639
15744
  }
15640
15745
  let signature = "";
15641
- const identity = this._identity;
15642
- if (identity?.private_key_pem) {
15746
+ const currentAid = this._currentAid;
15747
+ if (currentAid?.privateKeyPem) {
15643
15748
  try {
15644
15749
  const signPayloadObj = {
15645
15750
  group_id: groupId,
@@ -15649,7 +15754,7 @@ var _AUNClient = class _AUNClient {
15649
15754
  };
15650
15755
  const signPayload = stableStringify(signPayloadObj);
15651
15756
  const signPayloadBytes = new TextEncoder().encode(signPayload);
15652
- const privKey = await importPrivateKeyEcdsa(identity.private_key_pem);
15757
+ const privKey = await importPrivateKeyEcdsa(currentAid.privateKeyPem);
15653
15758
  const sigBytes = await ecdsaSignDer(privKey, signPayloadBytes);
15654
15759
  signature = uint8ToBase64(sigBytes);
15655
15760
  } catch (sigExc) {
@@ -15823,7 +15928,7 @@ var _AUNClient = class _AUNClient {
15823
15928
  if (newContig > 0 && newContig !== contigBefore) {
15824
15929
  const maxSeen = this._seqTracker.getMaxSeenSeq(ns);
15825
15930
  const ackSeq = maxSeen > 0 ? Math.min(newContig, maxSeen) : newContig;
15826
- this.call("message.v2.ack", { up_to_seq: ackSeq }).catch((e) => this._clientLog.debug(`V2 P2P push-ack failed: ${e}`));
15931
+ this._callRawV2Rpc("message.v2.ack", { up_to_seq: ackSeq }).catch((e) => this._clientLog.debug(`V2 P2P push-ack failed: ${e}`));
15827
15932
  }
15828
15933
  this._clientLog.debug(
15829
15934
  `_onV2PushNotification: push \u5E26 payload \u89E3\u5BC6\u6210\u529F, contiguous_seq=${contigBefore}->${newContig} push_seq=${pushSeq}`
@@ -16153,10 +16258,6 @@ function parseCertCN(certPem) {
16153
16258
  return null;
16154
16259
  }
16155
16260
  }
16156
- function normalizeSlotId(slotId) {
16157
- const value = String(slotId ?? "default").trim();
16158
- return value || "default";
16159
- }
16160
16261
  function issuerFromAid(aid) {
16161
16262
  const target = String(aid ?? "").trim();
16162
16263
  const dotIdx = target.indexOf(".");
@@ -16219,7 +16320,10 @@ var AIDStore = class {
16219
16320
  this._encryptionSeed = String(opts.encryptionSeed ?? "");
16220
16321
  this.deviceId = opts.deviceId ? normalizeInstanceId(opts.deviceId, "deviceId", { allowEmpty: true }) : getDeviceId();
16221
16322
  this.slotId = normalizeSlotId(opts.slotId);
16222
- this._verifySsl = opts.verifySsl ?? true;
16323
+ if (opts.verifySsl === false) {
16324
+ console.warn("[aun_core.config] verify_ssl=false \u5728\u6D4F\u89C8\u5668\u73AF\u5883\u4E2D\u4E0D\u53D7\u652F\u6301\uFF0CSSL \u8BC1\u4E66\u9A8C\u8BC1\u5C06\u4FDD\u6301\u542F\u7528\u3002");
16325
+ }
16326
+ this._verifySsl = opts.verifySsl === false ? true : opts.verifySsl ?? true;
16223
16327
  this._keystore = new IndexedDBKeyStore({ encryptionSeed: this._encryptionSeed || void 0 });
16224
16328
  this._crypto = new CryptoProvider();
16225
16329
  this._discovery = new GatewayDiscovery();