@meshconnect/uwc-core 2.5.16-snapshot.da6ba82 → 2.6.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.
Files changed (38) hide show
  1. package/README.md +2 -2
  2. package/dist/events.d.ts +10 -0
  3. package/dist/events.d.ts.map +1 -1
  4. package/dist/events.js.map +1 -1
  5. package/dist/observability/instrument-handoff.d.ts +2 -0
  6. package/dist/observability/instrument-handoff.d.ts.map +1 -1
  7. package/dist/observability/instrument-handoff.js +6 -0
  8. package/dist/observability/instrument-handoff.js.map +1 -1
  9. package/dist/observability/telemetry.d.ts +2 -0
  10. package/dist/observability/telemetry.d.ts.map +1 -1
  11. package/dist/observability/telemetry.js +15 -21
  12. package/dist/observability/telemetry.js.map +1 -1
  13. package/dist/services/connection-service.d.ts +5 -0
  14. package/dist/services/connection-service.d.ts.map +1 -1
  15. package/dist/services/connection-service.js +21 -4
  16. package/dist/services/connection-service.js.map +1 -1
  17. package/dist/universal-wallet-connector.d.ts +7 -0
  18. package/dist/universal-wallet-connector.d.ts.map +1 -1
  19. package/dist/universal-wallet-connector.js +3 -2
  20. package/dist/universal-wallet-connector.js.map +1 -1
  21. package/dist/utils/to-wallet-error.d.ts.map +1 -1
  22. package/dist/utils/to-wallet-error.js +7 -8
  23. package/dist/utils/to-wallet-error.js.map +1 -1
  24. package/dist/version.d.ts +1 -1
  25. package/dist/version.d.ts.map +1 -1
  26. package/dist/version.js +1 -1
  27. package/dist/version.js.map +1 -1
  28. package/package.json +5 -5
  29. package/src/events.ts +10 -0
  30. package/src/observability/instrument-handoff.ts +8 -0
  31. package/src/observability/telemetry.test.ts +0 -59
  32. package/src/observability/telemetry.ts +17 -22
  33. package/src/services/connection-service.test.ts +113 -1
  34. package/src/services/connection-service.ts +30 -4
  35. package/src/universal-wallet-connector.ts +10 -2
  36. package/src/utils/to-wallet-error.test.ts +11 -19
  37. package/src/utils/to-wallet-error.ts +6 -7
  38. package/src/version.ts +1 -1
@@ -26,6 +26,11 @@ export interface ServiceOptions {
26
26
  * Forwarded verbatim to the connector; see `ConnectorConnectOptions`.
27
27
  */
28
28
  requiredAddresses?: readonly string[]
29
+ /**
30
+ * Connect only if the wallet already trusts this origin (connect only).
31
+ * Injected mode only; see `ConnectorConnectOptions.silentOnly`.
32
+ */
33
+ silentOnly?: boolean
29
34
  }
30
35
 
31
36
  /** Sibling-namespace live-account re-read poll: absorbs the lag while a wallet
@@ -101,6 +106,17 @@ export class ConnectionService {
101
106
  const provider = this.getProviderForMode(wallet, connectionMode)
102
107
  const network = this.validateAndDetermineNetwork(networkId, provider)
103
108
  const connector = this.getConnector(connectionMode)
109
+ // A silent-only connect is a promise never to open wallet UI. Only the
110
+ // injected connector can keep it — WalletConnect / TON Connect always hand
111
+ // off to the wallet — so refuse the rest here, as a validation failure:
112
+ // before `connecting`, so the attempt never enters the hand-off funnel.
113
+ // A plain Error, not `WalletNotAuthorizedError`: that classifies as the
114
+ // expected `not_authorized` miss, which would hide this caller bug.
115
+ if (options?.silentOnly && connectionMode !== 'injected') {
116
+ throw new Error(
117
+ `silentOnly is not supported for connection mode '${connectionMode}'`
118
+ )
119
+ }
104
120
  const connectAttemptId = generateId()
105
121
 
106
122
  // Supersede any prior in-flight attempt: abort it so its URI poll and
@@ -157,7 +173,10 @@ export class ConnectionService {
157
173
  walletId,
158
174
  namespace: network.namespace,
159
175
  chainId: network.id,
160
- connectAttemptId
176
+ connectAttemptId,
177
+ // Lets telemetry tell a silent restore from a tapped connect: both
178
+ // succeed the same way, and only a miss carries a distinct failureKind.
179
+ silentOnly: options?.silentOnly === true
161
180
  },
162
181
  async handoffId => {
163
182
  // Publish this attempt's routing for the connector's step sink.
@@ -170,7 +189,8 @@ export class ConnectionService {
170
189
  provider,
171
190
  signal,
172
191
  connectAttemptId,
173
- options?.requiredAddresses
192
+ options?.requiredAddresses,
193
+ options?.silentOnly
174
194
  )
175
195
  } finally {
176
196
  // Retract ONLY if we are still the published attempt. An
@@ -261,7 +281,8 @@ export class ConnectionService {
261
281
  provider: SupportedProvider,
262
282
  signal: AbortSignal,
263
283
  connectAttemptId: string,
264
- requiredAddresses?: readonly string[]
284
+ requiredAddresses?: readonly string[],
285
+ silentOnly?: boolean
265
286
  ): Promise<ConnectorResult> {
266
287
  // Race the connector call against the AbortSignal so a mid-flight abort
267
288
  // (e.g. user cancels the WalletConnect QR while the prompt is open)
@@ -274,7 +295,12 @@ export class ConnectionService {
274
295
  provider as
275
296
  | ExtensionInjectedProvider
276
297
  | IntegratedBrowserInjectedProvider,
277
- requiredAddresses ? { requiredAddresses } : undefined
298
+ requiredAddresses || silentOnly
299
+ ? {
300
+ ...(requiredAddresses ? { requiredAddresses } : {}),
301
+ ...(silentOnly ? { silentOnly } : {})
302
+ }
303
+ : undefined
278
304
  ),
279
305
  signal
280
306
  )
@@ -130,6 +130,13 @@ export interface ConnectOptions extends OperationOptions {
130
130
  * constraint.
131
131
  */
132
132
  requiredAddresses?: readonly string[]
133
+ /**
134
+ * Connect only if the wallet already trusts this origin; never prompt.
135
+ * Forwarded to the connector as {@link ConnectorConnectOptions.silentOnly}
136
+ * — see there for the semantics. `'injected'` mode only: any other mode
137
+ * rejects with a plain `Error` before reaching the wallet.
138
+ */
139
+ silentOnly?: boolean
133
140
  }
134
141
 
135
142
  export class UniversalWalletConnector {
@@ -473,8 +480,9 @@ export class UniversalWalletConnector {
473
480
  UniversalWalletConnector.instance = this
474
481
  }
475
482
 
476
- // Initialize detected wallets after services are created
477
- this.initializeDetectedWallets()
483
+ // Initialize detected wallets after services are created. Fire-and-forget on
484
+ // purpose (a constructor can't await); the method catches everything itself.
485
+ void this.initializeDetectedWallets()
478
486
  }
479
487
 
480
488
  /**
@@ -1,7 +1,8 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import {
3
3
  WalletConnectorError,
4
- NoCommonNetworkError
4
+ NoCommonNetworkError,
5
+ WalletNotAuthorizedError
5
6
  } from '@meshconnect/uwc-types'
6
7
  import {
7
8
  classifyError,
@@ -38,6 +39,15 @@ describe('classifyError', () => {
38
39
  })
39
40
  })
40
41
 
42
+ it('classifies WalletNotAuthorizedError as not_authorized/connector (ONC-1975)', () => {
43
+ // A silent-only connect that found no authorization. Expected, not a
44
+ // fault, so it gets its own kind that failure rates can exclude.
45
+ expect(classifyError(new WalletNotAuthorizedError())).toEqual({
46
+ failureKind: 'not_authorized',
47
+ source: 'connector'
48
+ })
49
+ })
50
+
41
51
  it('classifies -32002 (request already pending) as provider_error', () => {
42
52
  // Delta B: the double-fire race. A provider-level error, not a user reject.
43
53
  expect(classifyError({ code: -32002, message: 'already pending' })).toEqual(
@@ -203,24 +213,6 @@ describe('toWalletError', () => {
203
213
  })
204
214
  })
205
215
 
206
- it('carries the provider reason of a connector error', () => {
207
- const err = new WalletConnectorError({
208
- type: 'unknown',
209
- message: 'An unknown RPC error occurred.',
210
- providerReason: 'cancelled'
211
- })
212
- expect(toWalletError(err)).toEqual({
213
- type: 'unknown',
214
- message: 'An unknown RPC error occurred.',
215
- providerReason: 'cancelled'
216
- })
217
- })
218
-
219
- it('omits providerReason when the connector error has none', () => {
220
- const err = new WalletConnectorError({ type: 'unknown', message: 'x' })
221
- expect(toWalletError(err)).not.toHaveProperty('providerReason')
222
- })
223
-
224
216
  it('bounds an over-long non-connector message (shared safeErrorMessage cap)', () => {
225
217
  const err = new Error('x'.repeat(10_000))
226
218
  expect(toWalletError(err).message).toHaveLength(500)
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  WalletConnectorError,
3
3
  NoCommonNetworkError,
4
+ WalletNotAuthorizedError,
4
5
  safeErrorMessage,
5
6
  type WalletError,
6
7
  type FailureKind,
@@ -26,13 +27,7 @@ const MAX_ERROR_CODE_LENGTH = 64
26
27
  export function toWalletError(error: unknown): WalletError {
27
28
  try {
28
29
  if (error instanceof WalletConnectorError) {
29
- return {
30
- type: error.type,
31
- message: error.message,
32
- ...(error.providerReason
33
- ? { providerReason: error.providerReason }
34
- : {})
35
- }
30
+ return { type: error.type, message: error.message }
36
31
  }
37
32
  return { type: 'unknown', message: safeErrorMessage(error) }
38
33
  } catch {
@@ -107,6 +102,10 @@ function classifyErrorUnguarded(error: unknown): {
107
102
  let failureKind: FailureKind = 'unknown'
108
103
  if (isUserRejection(error)) {
109
104
  failureKind = 'user_rejected'
105
+ } else if (error instanceof WalletNotAuthorizedError) {
106
+ // A silent-only connect stopped because the wallet hasn't authorized this
107
+ // origin. Nothing was shown to the user, so it is expected, not a fault.
108
+ failureKind = 'not_authorized'
110
109
  } else if (error instanceof NoCommonNetworkError) {
111
110
  // The wallet and configured networks don't overlap — the #1 prod connection
112
111
  // failure. Carries its own CAIP-2 id lists; the caller forwards them.
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated from package.json by scripts/generate-version.mjs — do not edit.
2
- export const UWC_CORE_VERSION = '2.5.16'
2
+ export const UWC_CORE_VERSION = '2.6.0'