@meshconnect/uwc-core 1.0.1-snapshot.c7e65ce → 1.0.2

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 (76) hide show
  1. package/README.md +66 -211
  2. package/dist/events.d.ts +2 -69
  3. package/dist/events.d.ts.map +1 -1
  4. package/dist/events.js +1 -40
  5. package/dist/events.js.map +1 -1
  6. package/dist/index.d.ts +0 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +0 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/managers/event-manager.d.ts.map +1 -1
  11. package/dist/managers/event-manager.js +1 -5
  12. package/dist/managers/event-manager.js.map +1 -1
  13. package/dist/services/connection-service.d.ts +1 -2
  14. package/dist/services/connection-service.d.ts.map +1 -1
  15. package/dist/services/connection-service.js +15 -35
  16. package/dist/services/connection-service.js.map +1 -1
  17. package/dist/services/network-switch-service.d.ts +1 -2
  18. package/dist/services/network-switch-service.d.ts.map +1 -1
  19. package/dist/services/network-switch-service.js +15 -33
  20. package/dist/services/network-switch-service.js.map +1 -1
  21. package/dist/universal-wallet-connector.d.ts +2 -51
  22. package/dist/universal-wallet-connector.d.ts.map +1 -1
  23. package/dist/universal-wallet-connector.js +61 -163
  24. package/dist/universal-wallet-connector.js.map +1 -1
  25. package/package.json +5 -5
  26. package/src/events.ts +1 -114
  27. package/src/index.ts +0 -6
  28. package/src/managers/event-manager.test.ts +0 -25
  29. package/src/managers/event-manager.ts +1 -5
  30. package/src/services/connection-service.test.ts +1 -66
  31. package/src/services/connection-service.ts +32 -54
  32. package/src/services/network-switch-service.test.ts +1 -51
  33. package/src/services/network-switch-service.ts +23 -43
  34. package/src/universal-wallet-connector.ts +71 -244
  35. package/dist/logger/create-logger.d.ts +0 -32
  36. package/dist/logger/create-logger.d.ts.map +0 -1
  37. package/dist/logger/create-logger.js +0 -69
  38. package/dist/logger/create-logger.js.map +0 -1
  39. package/dist/observability/connect-observer.d.ts +0 -22
  40. package/dist/observability/connect-observer.d.ts.map +0 -1
  41. package/dist/observability/connect-observer.js +0 -60
  42. package/dist/observability/connect-observer.js.map +0 -1
  43. package/dist/observability/instrument-handoff.d.ts +0 -39
  44. package/dist/observability/instrument-handoff.d.ts.map +0 -1
  45. package/dist/observability/instrument-handoff.js +0 -86
  46. package/dist/observability/instrument-handoff.js.map +0 -1
  47. package/dist/observability/scrub.d.ts +0 -30
  48. package/dist/observability/scrub.d.ts.map +0 -1
  49. package/dist/observability/scrub.js +0 -135
  50. package/dist/observability/scrub.js.map +0 -1
  51. package/dist/observability/telemetry.d.ts +0 -77
  52. package/dist/observability/telemetry.d.ts.map +0 -1
  53. package/dist/observability/telemetry.js +0 -138
  54. package/dist/observability/telemetry.js.map +0 -1
  55. package/dist/utils/id.d.ts +0 -2
  56. package/dist/utils/id.d.ts.map +0 -1
  57. package/dist/utils/id.js +0 -41
  58. package/dist/utils/id.js.map +0 -1
  59. package/dist/utils/to-wallet-error.d.ts +0 -16
  60. package/dist/utils/to-wallet-error.d.ts.map +0 -1
  61. package/dist/utils/to-wallet-error.js +0 -33
  62. package/dist/utils/to-wallet-error.js.map +0 -1
  63. package/src/logger/create-logger.test.ts +0 -111
  64. package/src/logger/create-logger.ts +0 -101
  65. package/src/observability/connect-observer.test.ts +0 -100
  66. package/src/observability/connect-observer.ts +0 -71
  67. package/src/observability/instrument-handoff.test.ts +0 -150
  68. package/src/observability/instrument-handoff.ts +0 -122
  69. package/src/observability/scrub.test.ts +0 -109
  70. package/src/observability/scrub.ts +0 -142
  71. package/src/observability/telemetry.test.ts +0 -134
  72. package/src/observability/telemetry.ts +0 -211
  73. package/src/universal-wallet-connector.observability.test.ts +0 -265
  74. package/src/utils/id.test.ts +0 -15
  75. package/src/utils/id.ts +0 -48
  76. package/src/utils/to-wallet-error.ts +0 -36
@@ -1,265 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest'
2
- import type {
3
- Network,
4
- WalletMetadata,
5
- Logger,
6
- Session
7
- } from '@meshconnect/uwc-types'
8
- import { UniversalWalletConnector } from './universal-wallet-connector'
9
- import type { UWCObserver, UWCTelemetryEvent } from './observability/telemetry'
10
-
11
- // Mock connectors + services so the façade resolves deterministically, but leave
12
- // the EventManager + logger + observability wiring REAL so this exercises the
13
- // actual end-to-end observer path through the public API.
14
- //
15
- // connect()/switchNetwork() instrumentation now lives INSIDE their services
16
- // (after validation) — covered by the service tests. Here we use signMessage,
17
- // which stays instrumented at the façade, to exercise the observer end-to-end.
18
- const signMessageMock = vi.fn()
19
-
20
- const connectedSession: Session = {
21
- connectionMode: 'injected',
22
- activeNetwork: {
23
- internalId: 1,
24
- id: 'eip155:1',
25
- namespace: 'eip155',
26
- name: 'Ethereum',
27
- logoUrl: '',
28
- nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
29
- networkType: 'evm'
30
- },
31
- activeWalletCapabilities: null,
32
- activeNetworkWalletCapabilities: null,
33
- activeAddress: '0xabc',
34
- publicKey: null,
35
- availableNetworks: [],
36
- activeWallet: {
37
- id: 'metamask',
38
- name: 'MetaMask',
39
- extensionInjectedProvider: {}
40
- } as unknown as WalletMetadata,
41
- availableAddresses: []
42
- }
43
-
44
- vi.mock('@meshconnect/uwc-injected-connector', () => ({
45
- InjectedConnector: vi.fn().mockImplementation(function () {
46
- return { getAvailableWallets: vi.fn().mockResolvedValue([]) }
47
- })
48
- }))
49
- vi.mock('@meshconnect/uwc-wallet-connect-connector', () => ({
50
- WalletConnectConnector: vi.fn().mockImplementation(function () {
51
- return { getAvailableWallets: vi.fn().mockResolvedValue([]) }
52
- })
53
- }))
54
- vi.mock('@meshconnect/uwc-ton-connector', () => ({
55
- TonConnectConnector: vi.fn().mockImplementation(function () {
56
- return { getAvailableWallets: vi.fn().mockResolvedValue([]) }
57
- })
58
- }))
59
- vi.mock('./managers/session-manager', () => ({
60
- SessionManager: vi.fn().mockImplementation(function () {
61
- return { getSession: () => connectedSession, updateSession: vi.fn() }
62
- })
63
- }))
64
- vi.mock('./services/connection-service', () => ({
65
- ConnectionService: vi.fn().mockImplementation(function () {
66
- return {
67
- connect: vi.fn().mockResolvedValue(undefined),
68
- disconnect: vi.fn().mockResolvedValue(undefined),
69
- getWallets: vi.fn().mockReturnValue([]),
70
- getNetworks: vi.fn().mockReturnValue([]),
71
- getConnectionURI: vi.fn(),
72
- updateWallets: vi.fn()
73
- }
74
- })
75
- }))
76
- vi.mock('./services/network-switch-service', () => ({
77
- NetworkSwitchService: vi.fn().mockImplementation(function () {
78
- return { switchNetwork: vi.fn(), getLoadingState: vi.fn() }
79
- })
80
- }))
81
- vi.mock('./services/signature-service', () => ({
82
- SignatureService: vi.fn().mockImplementation(function () {
83
- return { signMessage: signMessageMock, signTypedData: vi.fn() }
84
- })
85
- }))
86
- vi.mock('./services/transaction-service', () => ({
87
- TransactionService: vi.fn().mockImplementation(function () {
88
- return { sendTransaction: vi.fn() }
89
- })
90
- }))
91
- vi.mock('./services/wallet-capabilities-service', () => ({
92
- WalletCapabilitiesService: vi.fn().mockImplementation(function () {
93
- return { getWalletCapabilities: vi.fn() }
94
- })
95
- }))
96
-
97
- const networks = [
98
- {
99
- internalId: 1,
100
- id: 'eip155:1',
101
- namespace: 'eip155',
102
- name: 'Ethereum',
103
- logoUrl: '',
104
- nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
105
- networkType: 'evm'
106
- }
107
- ] as unknown as Network[]
108
-
109
- const wallets = [
110
- { id: 'metamask', name: 'MetaMask' }
111
- ] as unknown as WalletMetadata[]
112
-
113
- describe('UniversalWalletConnector — observability wiring', () => {
114
- beforeEach(() => {
115
- UniversalWalletConnector.resetInstance()
116
- signMessageMock.mockReset()
117
- signMessageMock.mockResolvedValue({ type: 'standard', signature: '0xsig' })
118
- })
119
-
120
- it('forwards a sign handoff to observer.onEvent (awaitingWallet → walletSucceeded)', async () => {
121
- const events: UWCTelemetryEvent[] = []
122
- const observer: UWCObserver = { onEvent: e => events.push(e) }
123
- const uwc = new UniversalWalletConnector({ networks, wallets, observer })
124
-
125
- await uwc.signMessage('hello')
126
-
127
- const names = events.map(e => e.name)
128
- expect(names).toContain('awaitingWallet')
129
- expect(names).toContain('walletSucceeded')
130
-
131
- const awaiting = events.find(e => e.name === 'awaitingWallet')!
132
- const succeeded = events.find(e => e.name === 'walletSucceeded')!
133
- // Same correlation id pairs start↔terminal, and the per-instance session id
134
- // is stamped on every record.
135
- expect(awaiting.handoffId).toBe(succeeded.handoffId)
136
- expect(awaiting.sdkSessionId).toBe(succeeded.sdkSessionId)
137
- expect(awaiting.operation).toBe('signMessage')
138
- expect(signMessageMock).toHaveBeenCalledOnce()
139
- })
140
-
141
- it('stamps a consumer-supplied correlationId (string) on every record', async () => {
142
- const events: UWCTelemetryEvent[] = []
143
- const uwc = new UniversalWalletConnector({
144
- networks,
145
- wallets,
146
- observer: { onEvent: e => events.push(e) },
147
- correlationId: 'link-123'
148
- })
149
-
150
- await uwc.signMessage('hello')
151
-
152
- expect(events.length).toBeGreaterThan(0)
153
- expect(events.every(e => e.sdkSessionId === 'link-123')).toBe(true)
154
- })
155
-
156
- it('resolves a correlationId getter per-event (dynamic id)', async () => {
157
- let id = 'a'
158
- const events: UWCTelemetryEvent[] = []
159
- const uwc = new UniversalWalletConnector({
160
- networks,
161
- wallets,
162
- observer: { onEvent: e => events.push(e) },
163
- correlationId: () => id
164
- })
165
-
166
- await uwc.signMessage('one')
167
- id = 'b'
168
- await uwc.signMessage('two')
169
-
170
- const ids = new Set(events.map(e => e.sdkSessionId))
171
- expect(ids.has('a')).toBe(true)
172
- expect(ids.has('b')).toBe(true)
173
- })
174
-
175
- it('falls back to the generated id when the correlationId getter throws', async () => {
176
- const events: UWCTelemetryEvent[] = []
177
- const uwc = new UniversalWalletConnector({
178
- networks,
179
- wallets,
180
- observer: { onEvent: e => events.push(e) },
181
- correlationId: () => {
182
- throw new Error('not ready')
183
- }
184
- })
185
-
186
- await uwc.signMessage('hello')
187
-
188
- expect(events.length).toBeGreaterThan(0)
189
- // A stable, non-empty fallback id is stamped — never a throw.
190
- expect(
191
- events.every(
192
- e => typeof e.sdkSessionId === 'string' && e.sdkSessionId.length > 0
193
- )
194
- ).toBe(true)
195
- })
196
-
197
- it('emits walletFailed when the underlying op throws', async () => {
198
- signMessageMock.mockRejectedValueOnce(new Error('relay down'))
199
- const events: UWCTelemetryEvent[] = []
200
- const uwc = new UniversalWalletConnector({
201
- networks,
202
- wallets,
203
- observer: { onEvent: e => events.push(e) }
204
- })
205
-
206
- await expect(uwc.signMessage('hello')).rejects.toThrow('relay down')
207
- const failed = events.find(e => e.name === 'walletFailed')
208
- expect(failed?.error?.message).toBe('relay down')
209
- // The back-compat `error` event still fires too.
210
- expect(events.some(e => e.name === 'error')).toBe(true)
211
- })
212
-
213
- it('an aborted op emits awaitingWallet with no terminal and no error', async () => {
214
- // A DOMException AbortError is an intentional cancellation, not a wallet
215
- // outcome: instrumentHandoff emits no terminal, and emitError must skip it
216
- // too (both paths share isAbortError).
217
- signMessageMock.mockRejectedValueOnce(
218
- new DOMException('Aborted', 'AbortError')
219
- )
220
- const events: UWCTelemetryEvent[] = []
221
- const uwc = new UniversalWalletConnector({
222
- networks,
223
- wallets,
224
- observer: { onEvent: e => events.push(e) }
225
- })
226
-
227
- await expect(uwc.signMessage('hello')).rejects.toThrow()
228
-
229
- const names = events.map(e => e.name)
230
- expect(names).toContain('awaitingWallet')
231
- expect(names).not.toContain('walletSucceeded')
232
- expect(names).not.toContain('walletRejected')
233
- expect(names).not.toContain('walletFailed')
234
- expect(names).not.toContain('error')
235
- })
236
-
237
- it('routes a custom logger as the sink and the multi-instance warning through it', () => {
238
- const calls: string[] = []
239
- const logger: Logger = {
240
- debug: () => {},
241
- info: () => {},
242
- warn: () => {},
243
- error: msg => calls.push(msg)
244
- }
245
- // First instance is fine; the SECOND triggers the multi-instance warning,
246
- // which must travel through the injected logger, not raw console.
247
- new UniversalWalletConnector({ networks, wallets, logger })
248
- new UniversalWalletConnector({ networks, wallets, logger })
249
-
250
- expect(calls.some(m => m.includes('Multiple instances'))).toBe(true)
251
- })
252
-
253
- it('dispose() stops further observer delivery', async () => {
254
- const events: UWCTelemetryEvent[] = []
255
- const uwc = new UniversalWalletConnector({
256
- networks,
257
- wallets,
258
- observer: { onEvent: e => events.push(e) }
259
- })
260
- uwc.dispose()
261
- events.length = 0
262
- await uwc.signMessage('hello')
263
- expect(events).toHaveLength(0)
264
- })
265
- })
@@ -1,15 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { generateId } from './id'
3
-
4
- describe('generateId', () => {
5
- it('produces unique values', () => {
6
- const ids = new Set(Array.from({ length: 1000 }, () => generateId()))
7
- expect(ids.size).toBe(1000)
8
- })
9
-
10
- it('produces a non-empty string', () => {
11
- const id = generateId()
12
- expect(typeof id).toBe('string')
13
- expect(id.length).toBeGreaterThan(0)
14
- })
15
- })
package/src/utils/id.ts DELETED
@@ -1,48 +0,0 @@
1
- /**
2
- * Generate a correlation id (RFC-4122 v4 when available).
3
- *
4
- * Used for the per-instance `sdkSessionId` and per-handoff `handoffId` — both are
5
- * opaque correlation tokens, never derived from wallet data (no address, no key).
6
- * Prefers the native `crypto.randomUUID()` (browsers + Node ≥ 16); falls back to a
7
- * `crypto.getRandomValues`-backed v4, and finally to a timestamp + monotonic
8
- * counter only in environments that expose neither. Correlation ids need to be
9
- * collision-resistant enough to pair a start event with its terminal — NOT
10
- * cryptographically unpredictable — so the last-resort branch uses no PRNG.
11
- */
12
- // Monotonic counter for the no-crypto fallback: guarantees per-process uniqueness
13
- // without any pseudo-random generator (correlation ids need uniqueness, not
14
- // unpredictability — and a counter is strictly more collision-resistant here).
15
- let fallbackCounter = 0
16
-
17
- export function generateId(): string {
18
- const c = typeof globalThis !== 'undefined' ? globalThis.crypto : undefined
19
-
20
- if (c?.randomUUID) {
21
- return c.randomUUID()
22
- }
23
-
24
- if (c?.getRandomValues) {
25
- const bytes = c.getRandomValues(new Uint8Array(16))
26
- // Set the version (4) and variant (10xx) bits per RFC 4122 §4.4.
27
- bytes[6] = (bytes[6]! & 0x0f) | 0x40
28
- bytes[8] = (bytes[8]! & 0x3f) | 0x80
29
- const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0'))
30
- return (
31
- hex.slice(0, 4).join('') +
32
- '-' +
33
- hex.slice(4, 6).join('') +
34
- '-' +
35
- hex.slice(6, 8).join('') +
36
- '-' +
37
- hex.slice(8, 10).join('') +
38
- '-' +
39
- hex.slice(10, 16).join('')
40
- )
41
- }
42
-
43
- // Last-resort fallback (no Web Crypto). Timestamp + monotonic counter keeps
44
- // ids unique within the process without a PRNG. Sufficient for correlation.
45
- return (
46
- 'uwc-' + Date.now().toString(36) + '-' + (fallbackCounter++).toString(36)
47
- )
48
- }
@@ -1,36 +0,0 @@
1
- import { WalletConnectorError, type WalletError } from '@meshconnect/uwc-types'
2
-
3
- /** Normalize any thrown value into the PII-light `WalletError` shape. */
4
- export function toWalletError(error: unknown): WalletError {
5
- if (error instanceof WalletConnectorError) {
6
- return { type: error.type, message: error.message }
7
- }
8
- return {
9
- type: 'unknown',
10
- message: error instanceof Error ? error.message : String(error)
11
- }
12
- }
13
-
14
- /**
15
- * Whether a thrown value is an explicit user rejection. Connectors usually wrap
16
- * these as `WalletConnectorError{type:'rejected'}`, but a raw EIP-1193 reject
17
- * (code `4001`) or ethers' `ACTION_REJECTED` can also reach the façade.
18
- */
19
- export function isUserRejection(error: unknown): boolean {
20
- if (error instanceof WalletConnectorError) return error.type === 'rejected'
21
- const code = (error as { code?: unknown } | null | undefined)?.code
22
- return code === 4001 || code === 'ACTION_REJECTED'
23
- }
24
-
25
- /**
26
- * Whether a thrown value is an intentional cancellation (AbortSignal / fetch
27
- * abort). Matched by `name` rather than `instanceof Error` because a real abort is
28
- * a `DOMException`, which is not an `Error` subclass in every runtime.
29
- */
30
- export function isAbortError(error: unknown): boolean {
31
- return (
32
- typeof error === 'object' &&
33
- error !== null &&
34
- (error as { name?: unknown }).name === 'AbortError'
35
- )
36
- }