@dynamic-labs-wallet/browser 1.1.22 → 1.1.23

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/index.cjs CHANGED
@@ -574,14 +574,14 @@ function meetsMinVersion(sdkVersion, { minVersionByNamespace, fallbackMinVersion
574
574
 
575
575
  /**
576
576
  * Datadog event name emitted on every signed-session nonce rejection (a 400 or
577
- * 401 from the backup/recovery endpoints). Log-only: lets us split the failure
577
+ * 403 from the backup/recovery endpoints). Log-only: lets us split the failure
578
578
  * bucket by `reason` and measure the true per-wallet unrecoverable rate
579
579
  * without changing any retry behavior. See DYNT-1599.
580
580
  */ const NONCE_FAILURE_EVENT = 'waas.signed_session.nonce_failure';
581
581
  /**
582
- * Reasons that represent a genuine session-key signature mismatch (the 401 the
583
- * server returns per DYNT-1282). Used to gate 401 instrumentation so callers
584
- * that reuse 401 for unrelated rejections don't pollute the failure metric.
582
+ * Reasons that represent a genuine session-key signature mismatch (the 403 the
583
+ * server returns per DYNT-1282). Used to gate 403 instrumentation so callers
584
+ * that reuse 403 for unrelated rejections don't pollute the failure metric.
585
585
  */ const SESSION_SIGNATURE_FAILURE_REASONS = new Set([
586
586
  'invalid_nonce_signature',
587
587
  'invalid_session_signature'
@@ -675,12 +675,12 @@ function meetsMinVersion(sdkVersion, { minVersionByNamespace, fallbackMinVersion
675
675
  let hasRefreshed = false;
676
676
  return async (error, attempt)=>{
677
677
  const status = getHttpStatus(error);
678
- // A 400 is a refreshable replay nonce; a 401 is a session-key mismatch the
679
- // server returns to break the refresh loop (DYNT-1282) — logged only when the
680
- // body classifies as a genuine session-signature failure so unrelated 401s
678
+ // A 400 is a refreshable replay nonce; a 403 is a session-key
679
+ // mismatch the server returns to break the refresh loop (DYNT-1282) — logged only
680
+ // when the body classifies as a genuine session-signature failure so unrelated 403s
681
681
  // (e.g. an exhausted add-signer grant) don't pollute the DYNT-1599 metric.
682
682
  // Only the 400 can actually refresh.
683
- const isSessionSignatureFailure = status === 401 && SESSION_SIGNATURE_FAILURE_REASONS.has(classifyNonceFailure(readErrorBody(error)));
683
+ const isSessionSignatureFailure = status === 403 && SESSION_SIGNATURE_FAILURE_REASONS.has(classifyNonceFailure(readErrorBody(error)));
684
684
  const shouldInstrument = status === 400 || isSessionSignatureFailure;
685
685
  if (shouldInstrument) {
686
686
  const willRefresh = status === 400 && !hasRefreshed && this.canRefresh && this.supportsReverseChannel();
@@ -878,6 +878,13 @@ const SIGNED_SESSION_FAILURE_STATUSES = new Set([
878
878
  400,
879
879
  401
880
880
  ]);
881
+ // CKS returns a session-key mismatch as 403. Other 403s (e.g. a rejected grant)
882
+ // are unrelated, so a 403 only counts when the backend code names a signature failure.
883
+ const SESSION_KEY_MISMATCH_STATUS = 403;
884
+ const SESSION_KEY_MISMATCH_REASONS = new Set([
885
+ 'invalid_nonce_signature',
886
+ 'invalid_session_signature'
887
+ ]);
881
888
  const NONCE_REASON_TO_BACKUP_REASON = {
882
889
  nonce_already_used: 'nonce_already_used',
883
890
  invalid_nonce_signature: 'invalid_nonce_signature',
@@ -890,13 +897,17 @@ const classifyWalletApiError = (error)=>{
890
897
  if (error.status === core.NETWORK_ERROR_STATUS) {
891
898
  return 'network';
892
899
  }
893
- if (!SIGNED_SESSION_FAILURE_STATUSES.has(error.status)) {
900
+ const isSignedSessionStatus = SIGNED_SESSION_FAILURE_STATUSES.has(error.status);
901
+ if (!isSignedSessionStatus && error.status !== SESSION_KEY_MISMATCH_STATUS) {
894
902
  return 'upload_failure';
895
903
  }
896
904
  const nonceReason = classifyNonceFailure({
897
905
  code: error.code,
898
906
  message: error.message
899
907
  });
908
+ if (!isSignedSessionStatus && !SESSION_KEY_MISMATCH_REASONS.has(nonceReason)) {
909
+ return 'upload_failure';
910
+ }
900
911
  return NONCE_REASON_TO_BACKUP_REASON[nonceReason];
901
912
  };
902
913
  const isNetworkLikeError = (error)=>{
package/index.esm.js CHANGED
@@ -575,14 +575,14 @@ function meetsMinVersion(sdkVersion, { minVersionByNamespace, fallbackMinVersion
575
575
 
576
576
  /**
577
577
  * Datadog event name emitted on every signed-session nonce rejection (a 400 or
578
- * 401 from the backup/recovery endpoints). Log-only: lets us split the failure
578
+ * 403 from the backup/recovery endpoints). Log-only: lets us split the failure
579
579
  * bucket by `reason` and measure the true per-wallet unrecoverable rate
580
580
  * without changing any retry behavior. See DYNT-1599.
581
581
  */ const NONCE_FAILURE_EVENT = 'waas.signed_session.nonce_failure';
582
582
  /**
583
- * Reasons that represent a genuine session-key signature mismatch (the 401 the
584
- * server returns per DYNT-1282). Used to gate 401 instrumentation so callers
585
- * that reuse 401 for unrelated rejections don't pollute the failure metric.
583
+ * Reasons that represent a genuine session-key signature mismatch (the 403 the
584
+ * server returns per DYNT-1282). Used to gate 403 instrumentation so callers
585
+ * that reuse 403 for unrelated rejections don't pollute the failure metric.
586
586
  */ const SESSION_SIGNATURE_FAILURE_REASONS = new Set([
587
587
  'invalid_nonce_signature',
588
588
  'invalid_session_signature'
@@ -676,12 +676,12 @@ function meetsMinVersion(sdkVersion, { minVersionByNamespace, fallbackMinVersion
676
676
  let hasRefreshed = false;
677
677
  return async (error, attempt)=>{
678
678
  const status = getHttpStatus(error);
679
- // A 400 is a refreshable replay nonce; a 401 is a session-key mismatch the
680
- // server returns to break the refresh loop (DYNT-1282) — logged only when the
681
- // body classifies as a genuine session-signature failure so unrelated 401s
679
+ // A 400 is a refreshable replay nonce; a 403 is a session-key
680
+ // mismatch the server returns to break the refresh loop (DYNT-1282) — logged only
681
+ // when the body classifies as a genuine session-signature failure so unrelated 403s
682
682
  // (e.g. an exhausted add-signer grant) don't pollute the DYNT-1599 metric.
683
683
  // Only the 400 can actually refresh.
684
- const isSessionSignatureFailure = status === 401 && SESSION_SIGNATURE_FAILURE_REASONS.has(classifyNonceFailure(readErrorBody(error)));
684
+ const isSessionSignatureFailure = status === 403 && SESSION_SIGNATURE_FAILURE_REASONS.has(classifyNonceFailure(readErrorBody(error)));
685
685
  const shouldInstrument = status === 400 || isSessionSignatureFailure;
686
686
  if (shouldInstrument) {
687
687
  const willRefresh = status === 400 && !hasRefreshed && this.canRefresh && this.supportsReverseChannel();
@@ -879,6 +879,13 @@ const SIGNED_SESSION_FAILURE_STATUSES = new Set([
879
879
  400,
880
880
  401
881
881
  ]);
882
+ // CKS returns a session-key mismatch as 403. Other 403s (e.g. a rejected grant)
883
+ // are unrelated, so a 403 only counts when the backend code names a signature failure.
884
+ const SESSION_KEY_MISMATCH_STATUS = 403;
885
+ const SESSION_KEY_MISMATCH_REASONS = new Set([
886
+ 'invalid_nonce_signature',
887
+ 'invalid_session_signature'
888
+ ]);
882
889
  const NONCE_REASON_TO_BACKUP_REASON = {
883
890
  nonce_already_used: 'nonce_already_used',
884
891
  invalid_nonce_signature: 'invalid_nonce_signature',
@@ -891,13 +898,17 @@ const classifyWalletApiError = (error)=>{
891
898
  if (error.status === NETWORK_ERROR_STATUS) {
892
899
  return 'network';
893
900
  }
894
- if (!SIGNED_SESSION_FAILURE_STATUSES.has(error.status)) {
901
+ const isSignedSessionStatus = SIGNED_SESSION_FAILURE_STATUSES.has(error.status);
902
+ if (!isSignedSessionStatus && error.status !== SESSION_KEY_MISMATCH_STATUS) {
895
903
  return 'upload_failure';
896
904
  }
897
905
  const nonceReason = classifyNonceFailure({
898
906
  code: error.code,
899
907
  message: error.message
900
908
  });
909
+ if (!isSignedSessionStatus && !SESSION_KEY_MISMATCH_REASONS.has(nonceReason)) {
910
+ return 'upload_failure';
911
+ }
901
912
  return NONCE_REASON_TO_BACKUP_REASON[nonceReason];
902
913
  };
903
914
  const isNetworkLikeError = (error)=>{
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dynamic-labs-wallet/browser",
3
- "version": "1.1.22",
3
+ "version": "1.1.23",
4
4
  "license": "Licensed under the Dynamic Labs, Inc. Terms Of Service (https://www.dynamic.xyz/terms-conditions)",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@dynamic-labs-wallet/core": "1.1.22",
7
+ "@dynamic-labs-wallet/core": "1.1.23",
8
8
  "@dynamic-labs-wallet/forward-mpc-client": "2.0.2",
9
- "@dynamic-labs-wallet/primitives": "1.1.22",
9
+ "@dynamic-labs-wallet/primitives": "1.1.23",
10
10
  "@dynamic-labs/sdk-api-core": "0.50.0",
11
11
  "@noble/curves": "1.8.0",
12
12
  "argon2id": "1.0.1",
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/backup/password/errors.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAElF;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GACjC,gBAAgB,GAChB,oBAAoB,GACpB,oBAAoB,GACpB,yBAAyB,GACzB,2BAA2B,GAC3B,gBAAgB,GAChB,oBAAoB,GACpB,oBAAoB,GACpB,gBAAgB,GAChB,oBAAoB,GACpB,mBAAmB,GACnB,2BAA2B,GAC3B,kBAAkB,GAClB,oBAAoB,GACpB,SAAS,GACT,SAAS,CAAC;AAEd;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6CAA6C;;;;;;;;;;;;;;;;;CAiBK,CAAC;AAEhE,eAAO,MAAM,yCAAyC,WAAY,yBAAyB,KAAG,OACvC,CAAC;AA4JxD;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,UAAW,OAAO,KAAG,yBAM5D,CAAC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/backup/password/errors.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAElF;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GACjC,gBAAgB,GAChB,oBAAoB,GACpB,oBAAoB,GACpB,yBAAyB,GACzB,2BAA2B,GAC3B,gBAAgB,GAChB,oBAAoB,GACpB,oBAAoB,GACpB,gBAAgB,GAChB,oBAAoB,GACpB,mBAAmB,GACnB,2BAA2B,GAC3B,kBAAkB,GAClB,oBAAoB,GACpB,SAAS,GACT,SAAS,CAAC;AAEd;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6CAA6C;;;;;;;;;;;;;;;;;CAiBK,CAAC;AAEhE,eAAO,MAAM,yCAAyC,WAAY,yBAAyB,KAAG,OACvC,CAAC;AAwKxD;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,UAAW,OAAO,KAAG,yBAM5D,CAAC"}
@@ -3,7 +3,7 @@ import type { ILogger } from '@dynamic-labs-wallet/core';
3
3
  type ShouldRetry = (error: unknown, attempt: number) => boolean | Promise<boolean>;
4
4
  /**
5
5
  * Datadog event name emitted on every signed-session nonce rejection (a 400 or
6
- * 401 from the backup/recovery endpoints). Log-only: lets us split the failure
6
+ * 403 from the backup/recovery endpoints). Log-only: lets us split the failure
7
7
  * bucket by `reason` and measure the true per-wallet unrecoverable rate
8
8
  * without changing any retry behavior. See DYNT-1599.
9
9
  */
@@ -11,7 +11,7 @@ export declare const NONCE_FAILURE_EVENT = "waas.signed_session.nonce_failure";
11
11
  /**
12
12
  * Coarse cause of a signed-session nonce rejection. `invalid_nonce_signature`
13
13
  * and `invalid_session_signature` (a bad/stale signing key that diverged from
14
- * the JWT-embedded session key — surfaced as a 401 since DYNT-1282) cannot be
14
+ * the JWT-embedded session key — surfaced as a 403 since DYNT-1282) cannot be
15
15
  * fixed by refreshing the nonce, whereas `nonce_already_used` (a consumed
16
16
  * replay nonce, a 400) can — so splitting them tells us whether the
17
17
  * refresh-and-retry path can actually help.