@dynamic-labs/waas 4.97.0 → 4.99.0

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 CHANGED
@@ -1,4 +1,31 @@
1
1
 
2
+ ## [4.99.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.98.0...v4.99.0) (2026-09-10)
3
+
4
+
5
+ ### Features
6
+
7
+ * **solana-core:** standalone sponsored ATA creation [v4 backport] ([#12366](https://github.com/dynamic-labs/dynamic-auth/issues/12366)) ([46d86c9](https://github.com/dynamic-labs/dynamic-auth/commit/46d86c9a1a04c45bf045acc5c6df792dcd4b3590))
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * do not report wallets installed from a provider selection router (v4) ([#12341](https://github.com/dynamic-labs/dynamic-auth/issues/12341)) ([6b02087](https://github.com/dynamic-labs/dynamic-auth/commit/6b02087685545bb6f672eb9040316d01489c82f4))
13
+ * **screening:** soften the blocked-wallet copy to be provider-neutral (v4) ([#12359](https://github.com/dynamic-labs/dynamic-auth/issues/12359)) ([d6772df](https://github.com/dynamic-labs/dynamic-auth/commit/d6772dfc1419811bfbc1d9cb1db58fe12274d397))
14
+ * **waas:** detach the superseded WaaS client from the iframe reverse channel (v4) ([#12349](https://github.com/dynamic-labs/dynamic-auth/issues/12349)) ([393253d](https://github.com/dynamic-labs/dynamic-auth/commit/393253d9e5934e039e21b85ed6ceded760e0f225)), closes [#11766](https://github.com/dynamic-labs/dynamic-auth/issues/11766) [#12348](https://github.com/dynamic-labs/dynamic-auth/issues/12348)
15
+
16
+ ## [4.98.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.97.0...v4.98.0) (2026-09-02)
17
+
18
+
19
+ ### Features
20
+
21
+ * **waas-evm:** route embedded EVM sends through gas sponsorship when enabled (V4) ([#12307](https://github.com/dynamic-labs/dynamic-auth/issues/12307)) ([d8e6b94](https://github.com/dynamic-labs/dynamic-auth/commit/d8e6b94dc86e1d48b66a246bf8bf0b857e7e69c4))
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * **sdk-react-core:** send a css overrides summary in sdkSettings telemetry (v4) ([#12330](https://github.com/dynamic-labs/dynamic-auth/issues/12330)) ([8547ee7](https://github.com/dynamic-labs/dynamic-auth/commit/8547ee7a7c3fef8de0ff384778f86542b809e7aa))
27
+ * **waas-svm:** apply overrideBlockhash before sponsorship [v4 backport] ([#12320](https://github.com/dynamic-labs/dynamic-auth/issues/12320)) ([0551f01](https://github.com/dynamic-labs/dynamic-auth/commit/0551f01953f5e623ac113b03e1b010d3dc58a81e)), closes [#10599](https://github.com/dynamic-labs/dynamic-auth/issues/10599) [#10599](https://github.com/dynamic-labs/dynamic-auth/issues/10599) [#10599](https://github.com/dynamic-labs/dynamic-auth/issues/10599) [#10599](https://github.com/dynamic-labs/dynamic-auth/issues/10599)
28
+
2
29
  ## [4.97.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.96.4...v4.97.0) (2026-08-27)
3
30
 
4
31
 
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.97.0";
6
+ var version = "4.99.0";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "4.97.0";
2
+ var version = "4.99.0";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/waas",
3
- "version": "4.97.0",
3
+ "version": "4.99.0",
4
4
  "type": "module",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -17,17 +17,17 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@dynamic-labs-sdk/client": "1.27.1",
20
- "@dynamic-labs/assert-package-version": "4.97.0",
20
+ "@dynamic-labs/assert-package-version": "4.99.0",
21
21
  "@dynamic-labs/sdk-api-core": "0.12.0",
22
- "@dynamic-labs-wallet/browser-wallet-client": "1.0.92",
23
- "@dynamic-labs-wallet/forward-mpc-client": "1.0.1",
24
- "@dynamic-labs/ethereum-core": "4.97.0",
25
- "@dynamic-labs/logger": "4.97.0",
26
- "@dynamic-labs/solana-core": "4.97.0",
27
- "@dynamic-labs/sui-core": "4.97.0",
28
- "@dynamic-labs/utils": "4.97.0",
29
- "@dynamic-labs/wallet-book": "4.97.0",
30
- "@dynamic-labs/wallet-connector-core": "4.97.0"
22
+ "@dynamic-labs-wallet/browser-wallet-client": "1.1.8",
23
+ "@dynamic-labs-wallet/forward-mpc-client": "2.0.2",
24
+ "@dynamic-labs/ethereum-core": "4.99.0",
25
+ "@dynamic-labs/logger": "4.99.0",
26
+ "@dynamic-labs/solana-core": "4.99.0",
27
+ "@dynamic-labs/sui-core": "4.99.0",
28
+ "@dynamic-labs/utils": "4.99.0",
29
+ "@dynamic-labs/wallet-book": "4.99.0",
30
+ "@dynamic-labs/wallet-connector-core": "4.99.0"
31
31
  },
32
32
  "peerDependencies": {}
33
33
  }
@@ -241,6 +241,31 @@ const withDynamicWaas = (BaseClass) => {
241
241
  return client;
242
242
  });
243
243
  }
244
+ /**
245
+ * Stops the client answering the iframe's session-scoped reverse-channel
246
+ * requests — the signed session and the 401 notification. Its key-share
247
+ * handlers stay attached until the client's own cleanup() has its ACK, so
248
+ * the iframe can still clear shares on logout.
249
+ *
250
+ * Returns false only if the attempt threw: the client may still be
251
+ * registered, so the caller must not revoke it. Never rethrows — this runs
252
+ * on the rotation and logout paths, where throwing would leave the caller
253
+ * with no client at all.
254
+ */
255
+ detachWaasClient(client, reason) {
256
+ var _a;
257
+ // The pinned browser-wallet-client predates detach(); this goes away with
258
+ // the version bump.
259
+ const detachable = client;
260
+ try {
261
+ (_a = detachable === null || detachable === void 0 ? void 0 : detachable.detach) === null || _a === void 0 ? void 0 : _a.call(detachable);
262
+ return true;
263
+ }
264
+ catch (error) {
265
+ this.instrument('[DynamicWaasMixin] WaaS client detach failed', Object.assign({ key: 'waas-client-detach-failed', operation: 'detachWaasClient', reason, time: 0 }, this.buildErrorInstrumentContext(error)));
266
+ return false;
267
+ }
268
+ }
244
269
  getWaasWalletClient(traceContext_1) {
245
270
  return _tslib.__awaiter(this, arguments, void 0, function* (traceContext, { forceRebuild = false } = {}) {
246
271
  var _a, _b;
@@ -250,11 +275,19 @@ const withDynamicWaas = (BaseClass) => {
250
275
  // available (see getWaasWalletConnector's live-token guard); otherwise
251
276
  // createDynamicWaasClient would throw "Auth token is required".
252
277
  if (forceRebuild) {
253
- // Revoke the previous client's nonce callback before dropping it.
254
- // The old DynamicWalletClient is not destroyed — it has no cancellation
255
- // API — but revoking its reverse-channel callback prevents it from
256
- // fetching fresh nonces and competing with the new client's recovery.
257
- (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
278
+ // Detach the superseded client, then revoke it — and never revoke one we
279
+ // did not detach. The reverse channel is page-wide and
280
+ // first-response-wins, so a revoked-but-still-attached client rejects
281
+ // instantly, beats the live client to every getSignedSessionId and
282
+ // poisons wallet creation for the life of the iframe. Two cases land
283
+ // there: a failed detach, and a concurrent rebuild, where
284
+ // createDynamicWaasClient has installed the new revoker but not yet
285
+ // returned the client it belongs to. The revoke stays as a guard for a
286
+ // caller still holding a direct reference.
287
+ const superseded = this.dynamicWaasClient;
288
+ if (superseded && this.detachWaasClient(superseded, 'force-rebuild')) {
289
+ (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
290
+ }
258
291
  this.revokeSignedSession = undefined;
259
292
  this.dynamicWaasClient = undefined;
260
293
  }
@@ -774,7 +807,28 @@ const withDynamicWaas = (BaseClass) => {
774
807
  });
775
808
  }
776
809
  }
777
- (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
810
+ // Detach synchronously: the cleanup() above removes the handlers too, but
811
+ // it is un-awaited and can sit on the channel's 5s timeout first, leaving
812
+ // this client in the race with its callback already revoked.
813
+ //
814
+ // Same guard as the rebuild path: never revoke a client we did not detach.
815
+ // waasClient is undefined whenever getWaasWalletClient threw (pending-auth
816
+ // scope, or a failed build), and a client installed concurrently would own
817
+ // the revoke we still hold — revoking that one while it is attached is the
818
+ // original bug.
819
+ const superseded = waasClient !== null && waasClient !== void 0 ? waasClient : this.dynamicWaasClient;
820
+ const detached = superseded
821
+ ? this.detachWaasClient(superseded, 'end-session')
822
+ : false;
823
+ // Revoke only while the revoker still belongs to the client we detached.
824
+ // endSession awaits the client, the active address and the key-share
825
+ // removal, and a rotation completing in any of those windows swaps both
826
+ // fields — revoking the live replacement while it is attached is the
827
+ // original bug. Detaching the captured client is unconditional: it is
828
+ // always safe, and it is the half that actually leaves the race.
829
+ if (detached && superseded === this.dynamicWaasClient) {
830
+ (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
831
+ }
778
832
  this.revokeSignedSession = undefined;
779
833
  this.dynamicWaasClient = undefined;
780
834
  });
@@ -82,6 +82,18 @@ export declare const withDynamicWaas: <T extends abstract new (...args: any[]) =
82
82
  getSignedSessionId: () => Promise<string>;
83
83
  };
84
84
  createDynamicWaasClient(traceContext?: TraceContext): Promise<DynamicWalletClient>;
85
+ /**
86
+ * Stops the client answering the iframe's session-scoped reverse-channel
87
+ * requests — the signed session and the 401 notification. Its key-share
88
+ * handlers stay attached until the client's own cleanup() has its ACK, so
89
+ * the iframe can still clear shares on logout.
90
+ *
91
+ * Returns false only if the attempt threw: the client may still be
92
+ * registered, so the caller must not revoke it. Never rethrows — this runs
93
+ * on the rotation and logout paths, where throwing would leave the caller
94
+ * with no client at all.
95
+ */
96
+ detachWaasClient(client: DynamicWalletClient | undefined, reason: string): boolean;
85
97
  getWaasWalletClient(traceContext?: TraceContext, { forceRebuild }?: {
86
98
  forceRebuild?: boolean;
87
99
  }): Promise<DynamicWalletClient>;
@@ -237,6 +237,31 @@ const withDynamicWaas = (BaseClass) => {
237
237
  return client;
238
238
  });
239
239
  }
240
+ /**
241
+ * Stops the client answering the iframe's session-scoped reverse-channel
242
+ * requests — the signed session and the 401 notification. Its key-share
243
+ * handlers stay attached until the client's own cleanup() has its ACK, so
244
+ * the iframe can still clear shares on logout.
245
+ *
246
+ * Returns false only if the attempt threw: the client may still be
247
+ * registered, so the caller must not revoke it. Never rethrows — this runs
248
+ * on the rotation and logout paths, where throwing would leave the caller
249
+ * with no client at all.
250
+ */
251
+ detachWaasClient(client, reason) {
252
+ var _a;
253
+ // The pinned browser-wallet-client predates detach(); this goes away with
254
+ // the version bump.
255
+ const detachable = client;
256
+ try {
257
+ (_a = detachable === null || detachable === void 0 ? void 0 : detachable.detach) === null || _a === void 0 ? void 0 : _a.call(detachable);
258
+ return true;
259
+ }
260
+ catch (error) {
261
+ this.instrument('[DynamicWaasMixin] WaaS client detach failed', Object.assign({ key: 'waas-client-detach-failed', operation: 'detachWaasClient', reason, time: 0 }, this.buildErrorInstrumentContext(error)));
262
+ return false;
263
+ }
264
+ }
240
265
  getWaasWalletClient(traceContext_1) {
241
266
  return __awaiter(this, arguments, void 0, function* (traceContext, { forceRebuild = false } = {}) {
242
267
  var _a, _b;
@@ -246,11 +271,19 @@ const withDynamicWaas = (BaseClass) => {
246
271
  // available (see getWaasWalletConnector's live-token guard); otherwise
247
272
  // createDynamicWaasClient would throw "Auth token is required".
248
273
  if (forceRebuild) {
249
- // Revoke the previous client's nonce callback before dropping it.
250
- // The old DynamicWalletClient is not destroyed — it has no cancellation
251
- // API — but revoking its reverse-channel callback prevents it from
252
- // fetching fresh nonces and competing with the new client's recovery.
253
- (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
274
+ // Detach the superseded client, then revoke it — and never revoke one we
275
+ // did not detach. The reverse channel is page-wide and
276
+ // first-response-wins, so a revoked-but-still-attached client rejects
277
+ // instantly, beats the live client to every getSignedSessionId and
278
+ // poisons wallet creation for the life of the iframe. Two cases land
279
+ // there: a failed detach, and a concurrent rebuild, where
280
+ // createDynamicWaasClient has installed the new revoker but not yet
281
+ // returned the client it belongs to. The revoke stays as a guard for a
282
+ // caller still holding a direct reference.
283
+ const superseded = this.dynamicWaasClient;
284
+ if (superseded && this.detachWaasClient(superseded, 'force-rebuild')) {
285
+ (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
286
+ }
254
287
  this.revokeSignedSession = undefined;
255
288
  this.dynamicWaasClient = undefined;
256
289
  }
@@ -770,7 +803,28 @@ const withDynamicWaas = (BaseClass) => {
770
803
  });
771
804
  }
772
805
  }
773
- (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
806
+ // Detach synchronously: the cleanup() above removes the handlers too, but
807
+ // it is un-awaited and can sit on the channel's 5s timeout first, leaving
808
+ // this client in the race with its callback already revoked.
809
+ //
810
+ // Same guard as the rebuild path: never revoke a client we did not detach.
811
+ // waasClient is undefined whenever getWaasWalletClient threw (pending-auth
812
+ // scope, or a failed build), and a client installed concurrently would own
813
+ // the revoke we still hold — revoking that one while it is attached is the
814
+ // original bug.
815
+ const superseded = waasClient !== null && waasClient !== void 0 ? waasClient : this.dynamicWaasClient;
816
+ const detached = superseded
817
+ ? this.detachWaasClient(superseded, 'end-session')
818
+ : false;
819
+ // Revoke only while the revoker still belongs to the client we detached.
820
+ // endSession awaits the client, the active address and the key-share
821
+ // removal, and a rotation completing in any of those windows swaps both
822
+ // fields — revoking the live replacement while it is attached is the
823
+ // original bug. Detaching the captured client is unconditional: it is
824
+ // always safe, and it is the half that actually leaves the race.
825
+ if (detached && superseded === this.dynamicWaasClient) {
826
+ (_a = this.revokeSignedSession) === null || _a === void 0 ? void 0 : _a.call(this);
827
+ }
774
828
  this.revokeSignedSession = undefined;
775
829
  this.dynamicWaasClient = undefined;
776
830
  });