@0xsequence/wallet-wdk 3.0.0-beta.17 → 3.0.0-beta.19
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +24 -0
- package/dist/dbs/auth-commitments.d.ts.map +1 -1
- package/dist/dbs/auth-keys.d.ts.map +1 -1
- package/dist/dbs/messages.d.ts.map +1 -1
- package/dist/dbs/passkey-credentials.d.ts.map +1 -1
- package/dist/dbs/recovery.d.ts.map +1 -1
- package/dist/dbs/signatures.d.ts.map +1 -1
- package/dist/dbs/transactions.d.ts.map +1 -1
- package/dist/dbs/wallets.d.ts.map +1 -1
- package/dist/identity/signer.d.ts +1 -1
- package/dist/identity/signer.d.ts.map +1 -1
- package/dist/sequence/handlers/devices.d.ts +1 -1
- package/dist/sequence/handlers/devices.d.ts.map +1 -1
- package/dist/sequence/handlers/devices.js +1 -1
- package/dist/sequence/handlers/guard.d.ts +1 -1
- package/dist/sequence/handlers/guard.d.ts.map +1 -1
- package/dist/sequence/handlers/guard.js +22 -19
- package/dist/sequence/handlers/identity.d.ts.map +1 -1
- package/dist/sequence/handlers/mnemonic.d.ts.map +1 -1
- package/dist/sequence/handlers/mnemonic.js +21 -18
- package/dist/sequence/handlers/otp.d.ts.map +1 -1
- package/dist/sequence/handlers/otp.js +2 -1
- package/dist/sequence/handlers/passkeys.d.ts +1 -1
- package/dist/sequence/handlers/passkeys.d.ts.map +1 -1
- package/dist/sequence/handlers/passkeys.js +1 -1
- package/dist/sequence/handlers/recovery.js +1 -1
- package/dist/sequence/manager.d.ts +2 -0
- package/dist/sequence/manager.d.ts.map +1 -1
- package/dist/sequence/manager.js +2 -1
- package/dist/sequence/messages.js +1 -1
- package/dist/sequence/recovery.d.ts +2 -0
- package/dist/sequence/recovery.d.ts.map +1 -1
- package/dist/sequence/recovery.js +75 -14
- package/dist/sequence/signers.d.ts.map +1 -1
- package/dist/sequence/signers.js +3 -1
- package/dist/sequence/transactions.js +1 -1
- package/dist/sequence/wallets.d.ts +1 -1
- package/dist/sequence/wallets.d.ts.map +1 -1
- package/dist/sequence/wallets.js +17 -18
- package/eslint.config.js +12 -0
- package/package.json +15 -13
- package/src/dbs/auth-commitments.ts +1 -1
- package/src/dbs/auth-keys.ts +1 -1
- package/src/dbs/messages.ts +1 -1
- package/src/dbs/passkey-credentials.ts +1 -1
- package/src/dbs/recovery.ts +1 -1
- package/src/dbs/signatures.ts +1 -1
- package/src/dbs/transactions.ts +1 -1
- package/src/dbs/wallets.ts +1 -1
- package/src/identity/signer.ts +3 -3
- package/src/sequence/handlers/authcode-pkce.ts +1 -1
- package/src/sequence/handlers/devices.ts +1 -1
- package/src/sequence/handlers/guard.ts +6 -4
- package/src/sequence/handlers/identity.ts +1 -1
- package/src/sequence/handlers/mnemonic.ts +5 -3
- package/src/sequence/handlers/otp.ts +2 -1
- package/src/sequence/handlers/passkeys.ts +1 -1
- package/src/sequence/handlers/recovery.ts +1 -1
- package/src/sequence/manager.ts +3 -1
- package/src/sequence/messages.ts +1 -1
- package/src/sequence/recovery.ts +157 -52
- package/src/sequence/signers.ts +3 -1
- package/src/sequence/transactions.ts +1 -1
- package/src/sequence/wallets.ts +19 -20
- package/test/authcode-pkce.test.ts +2 -3
- package/test/authcode.test.ts +6 -8
- package/test/constants.ts +4 -2
- package/test/guard.test.ts +5 -5
- package/test/identity-signer.test.ts +1 -1
- package/test/otp.test.ts +1 -1
- package/test/passkeys.test.ts +1 -1
- package/test/recovery.test.ts +3 -3
- package/test/sessions.test.ts +1 -1
- package/test/{test-ssr-safety.mjs → test-ssr-safety.js} +143 -137
- package/test/transactions.test.ts +3 -3
- package/test/wallets.test.ts +5 -5
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* global console, process */
|
|
2
3
|
/**
|
|
3
4
|
* Comprehensive SSR Safety Test (Runtime Execution)
|
|
4
|
-
*
|
|
5
|
+
*
|
|
5
6
|
* This script tests that the entire wdk package can be imported and used in a Node.js
|
|
6
7
|
* environment (SSR context) without throwing errors about missing window.
|
|
7
|
-
*
|
|
8
|
+
*
|
|
8
9
|
* It executes the code at runtime to catch any SSR issues.
|
|
9
|
-
*
|
|
10
|
+
*
|
|
10
11
|
* Run with: node test-ssr-comprehensive.mjs
|
|
11
12
|
*/
|
|
12
13
|
|
|
@@ -52,24 +53,25 @@ try {
|
|
|
52
53
|
// Use the package name from package.json
|
|
53
54
|
const packageName = packageJson.name
|
|
54
55
|
console.log(`Importing ${packageName}...`)
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
// Try to resolve the package
|
|
57
58
|
const packagePath = require.resolve(packageName)
|
|
58
59
|
console.log(` Package resolved to: ${packagePath}`)
|
|
59
|
-
|
|
60
|
+
|
|
60
61
|
// Import the package
|
|
61
62
|
wdk = await import(packageName)
|
|
62
63
|
console.log('✓ Successfully imported package')
|
|
63
64
|
console.log(' Top-level exports:', Object.keys(wdk))
|
|
64
|
-
|
|
65
65
|
} catch (error) {
|
|
66
66
|
// Check if it's an SSR-related error
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
if (
|
|
68
|
+
error.message.includes('window is not defined') ||
|
|
69
|
+
error.message.includes('window') ||
|
|
70
|
+
error.message.includes('document is not defined') ||
|
|
71
|
+
error.message.includes('document') ||
|
|
72
|
+
error.message.includes('localStorage') ||
|
|
73
|
+
error.message.includes('sessionStorage')
|
|
74
|
+
) {
|
|
73
75
|
errors.push(`SSR ERROR: Package accesses browser globals at module load time: ${error.message}`)
|
|
74
76
|
if (error.stack) {
|
|
75
77
|
console.error('\nError stack:')
|
|
@@ -81,7 +83,7 @@ try {
|
|
|
81
83
|
console.error('Stack:', error.stack)
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
|
-
|
|
86
|
+
|
|
85
87
|
// Don't exit immediately - let the summary show the error
|
|
86
88
|
if (errors.length > 0) {
|
|
87
89
|
// Skip remaining tests if import failed
|
|
@@ -98,83 +100,84 @@ if (!wdk) {
|
|
|
98
100
|
console.log('Skipping - package import failed')
|
|
99
101
|
} else {
|
|
100
102
|
async function testExports(obj, path = '', depth = 0) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
103
|
+
if (depth > 5) return // Prevent infinite recursion
|
|
104
|
+
|
|
105
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
106
|
+
const currentPath = path ? `${path}.${key}` : key
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
// Skip if it's a circular reference or already tested
|
|
110
|
+
if (value === null || value === undefined) {
|
|
111
|
+
continue
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Test accessing the value (this executes any getters)
|
|
115
|
+
const accessed = value
|
|
116
|
+
|
|
117
|
+
// Test different types
|
|
118
|
+
if (typeof accessed === 'function') {
|
|
119
|
+
// Try to get function properties
|
|
120
|
+
try {
|
|
121
|
+
const props = Object.getOwnPropertyNames(accessed)
|
|
122
|
+
if (props.length > 0 && depth < 3) {
|
|
123
|
+
// Test static properties on functions
|
|
124
|
+
for (const prop of props.slice(0, 3)) {
|
|
125
|
+
try {
|
|
126
|
+
const propValue = accessed[prop]
|
|
127
|
+
if (typeof propValue === 'object' && propValue !== null && depth < 2) {
|
|
128
|
+
await testExports(propValue, `${currentPath}.${prop}`, depth + 1)
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
if (err.message.includes('window') || err.message.includes('document')) {
|
|
132
|
+
errors.push(`${currentPath}.${prop}: ${err.message}`)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
if (err.message.includes('window') || err.message.includes('document')) {
|
|
139
|
+
errors.push(`${currentPath}: ${err.message}`)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} else if (typeof accessed === 'object' && accessed !== null) {
|
|
143
|
+
// Test object properties
|
|
144
|
+
if (Array.isArray(accessed)) {
|
|
145
|
+
// Test array elements
|
|
146
|
+
for (let i = 0; i < Math.min(accessed.length, 3); i++) {
|
|
123
147
|
try {
|
|
124
|
-
const
|
|
125
|
-
if (typeof
|
|
126
|
-
await testExports(
|
|
148
|
+
const item = accessed[i]
|
|
149
|
+
if (typeof item === 'object' && item !== null && depth < 3) {
|
|
150
|
+
await testExports(item, `${currentPath}[${i}]`, depth + 1)
|
|
127
151
|
}
|
|
128
152
|
} catch (err) {
|
|
129
153
|
if (err.message.includes('window') || err.message.includes('document')) {
|
|
130
|
-
errors.push(`${currentPath}
|
|
154
|
+
errors.push(`${currentPath}[${i}]: ${err.message}`)
|
|
131
155
|
}
|
|
132
156
|
}
|
|
133
157
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
errors.push(`${currentPath}: ${err.message}`)
|
|
158
|
+
} else {
|
|
159
|
+
// Test object properties recursively
|
|
160
|
+
await testExports(accessed, currentPath, depth + 1)
|
|
138
161
|
}
|
|
139
162
|
}
|
|
140
|
-
}
|
|
141
|
-
//
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
for (let i = 0; i < Math.min(accessed.length, 3); i++) {
|
|
145
|
-
try {
|
|
146
|
-
const item = accessed[i]
|
|
147
|
-
if (typeof item === 'object' && item !== null && depth < 3) {
|
|
148
|
-
await testExports(item, `${currentPath}[${i}]`, depth + 1)
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
if (err.message.includes('window') || err.message.includes('document')) {
|
|
152
|
-
errors.push(`${currentPath}[${i}]: ${err.message}`)
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
// Test object properties recursively
|
|
158
|
-
await testExports(accessed, currentPath, depth + 1)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
} catch (error) {
|
|
163
|
-
// Check if it's an SSR-related error
|
|
164
|
-
if (error.message.includes('window is not defined') ||
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// Check if it's an SSR-related error
|
|
165
|
+
if (
|
|
166
|
+
error.message.includes('window is not defined') ||
|
|
165
167
|
error.message.includes('window') ||
|
|
166
168
|
error.message.includes('document is not defined') ||
|
|
167
169
|
error.message.includes('document') ||
|
|
168
170
|
error.message.includes('localStorage') ||
|
|
169
|
-
error.message.includes('sessionStorage')
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
error.message.includes('sessionStorage')
|
|
172
|
+
) {
|
|
173
|
+
errors.push(`${currentPath}: ${error.message}`)
|
|
174
|
+
} else {
|
|
175
|
+
// Other errors are warnings (might be expected, like missing dependencies)
|
|
176
|
+
warnings.push(`${currentPath}: ${error.message}`)
|
|
177
|
+
}
|
|
174
178
|
}
|
|
175
179
|
}
|
|
176
180
|
}
|
|
177
|
-
}
|
|
178
181
|
|
|
179
182
|
// Test all top-level exports
|
|
180
183
|
console.log('Testing all exports recursively...')
|
|
@@ -191,43 +194,46 @@ if (!wdk) {
|
|
|
191
194
|
} else {
|
|
192
195
|
// Test ManagerOptionsDefaults
|
|
193
196
|
try {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
197
|
+
if (wdk.Sequence?.ManagerOptionsDefaults) {
|
|
198
|
+
console.log('Testing ManagerOptionsDefaults...')
|
|
199
|
+
const defaults = wdk.Sequence.ManagerOptionsDefaults
|
|
200
|
+
|
|
201
|
+
// Access all properties
|
|
202
|
+
Object.keys(defaults).forEach((key) => {
|
|
203
|
+
try {
|
|
204
|
+
const value = defaults[key]
|
|
205
|
+
console.log(` ✓ ${key}: ${typeof value}`)
|
|
206
|
+
|
|
207
|
+
// If it's a function, try calling it
|
|
208
|
+
if (typeof value === 'function' && key === 'relayers') {
|
|
209
|
+
const result = value()
|
|
210
|
+
console.log(
|
|
211
|
+
` Called ${key}(), returned:`,
|
|
212
|
+
Array.isArray(result) ? `${result.length} items` : typeof result,
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
} catch (err) {
|
|
216
|
+
if (err.message.includes('window') || err.message.includes('document')) {
|
|
217
|
+
errors.push(`ManagerOptionsDefaults.${key}: ${err.message}`)
|
|
218
|
+
}
|
|
212
219
|
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
} catch (err) {
|
|
223
|
+
if (err.message.includes('window') || err.message.includes('document')) {
|
|
224
|
+
errors.push(`ManagerOptionsDefaults: ${err.message}`)
|
|
225
|
+
}
|
|
219
226
|
}
|
|
220
|
-
}
|
|
221
227
|
|
|
222
|
-
// Test applyManagerOptionsDefaults function
|
|
223
|
-
try {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
} catch (err) {
|
|
228
|
+
// Test applyManagerOptionsDefaults function
|
|
229
|
+
try {
|
|
230
|
+
if (wdk.Sequence?.applyManagerOptionsDefaults) {
|
|
231
|
+
console.log('Testing applyManagerOptionsDefaults...')
|
|
232
|
+
const result = wdk.Sequence.applyManagerOptionsDefaults()
|
|
233
|
+
console.log(' ✓ Function executed successfully')
|
|
234
|
+
console.log(' Result keys:', Object.keys(result).slice(0, 5).join(', '), '...')
|
|
235
|
+
}
|
|
236
|
+
} catch (err) {
|
|
231
237
|
if (err.message.includes('window') || err.message.includes('document')) {
|
|
232
238
|
errors.push(`applyManagerOptionsDefaults: ${err.message}`)
|
|
233
239
|
}
|
|
@@ -244,37 +250,37 @@ if (!wdk) {
|
|
|
244
250
|
} else {
|
|
245
251
|
// Get the package path and try importing from dist
|
|
246
252
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
253
|
+
const packagePath = require.resolve(packageJson.name)
|
|
254
|
+
const packageDir = dirname(packagePath)
|
|
255
|
+
|
|
256
|
+
// Try to import from the exports field if available
|
|
257
|
+
if (packageJson.exports) {
|
|
258
|
+
for (const [exportPath, exportConfig] of Object.entries(packageJson.exports)) {
|
|
259
|
+
if (exportPath === '.') {
|
|
260
|
+
const modulePath = exportConfig.default || exportConfig.types
|
|
261
|
+
if (modulePath) {
|
|
262
|
+
try {
|
|
263
|
+
const fullPath = join(packageDir, '..', modulePath)
|
|
264
|
+
console.log(`Testing import from ${exportPath}...`)
|
|
265
|
+
const subModule = await import(fullPath)
|
|
266
|
+
console.log(` ✓ Imported successfully`)
|
|
267
|
+
|
|
268
|
+
// Test accessing exports
|
|
269
|
+
const subExports = Object.keys(subModule)
|
|
270
|
+
if (subExports.length > 0) {
|
|
271
|
+
console.log(` Exports: ${subExports.slice(0, 5).join(', ')}${subExports.length > 5 ? '...' : ''}`)
|
|
272
|
+
}
|
|
273
|
+
} catch (err) {
|
|
274
|
+
if (err.message.includes('window') || err.message.includes('document')) {
|
|
275
|
+
errors.push(`Import ${exportPath}: ${err.message}`)
|
|
276
|
+
} else if (!err.message.includes('Cannot find module')) {
|
|
277
|
+
warnings.push(`Import ${exportPath}: ${err.message}`)
|
|
278
|
+
}
|
|
272
279
|
}
|
|
273
280
|
}
|
|
274
281
|
}
|
|
275
282
|
}
|
|
276
283
|
}
|
|
277
|
-
}
|
|
278
284
|
} catch (err) {
|
|
279
285
|
warnings.push(`Could not test sub-modules: ${err.message}`)
|
|
280
286
|
}
|
|
@@ -290,7 +296,7 @@ if (errors.length === 0) {
|
|
|
290
296
|
console.log('The package can be safely imported and used in a Node.js/SSR environment.')
|
|
291
297
|
if (warnings.length > 0) {
|
|
292
298
|
console.log(`\n⚠️ ${warnings.length} warning(s) (non-SSR related):`)
|
|
293
|
-
warnings.slice(0, 5).forEach(warn => console.log(` - ${warn}`))
|
|
299
|
+
warnings.slice(0, 5).forEach((warn) => console.log(` - ${warn}`))
|
|
294
300
|
if (warnings.length > 5) {
|
|
295
301
|
console.log(` ... and ${warnings.length - 5} more`)
|
|
296
302
|
}
|
|
@@ -298,11 +304,11 @@ if (errors.length === 0) {
|
|
|
298
304
|
process.exit(0)
|
|
299
305
|
} else {
|
|
300
306
|
console.log('\n❌ ERRORS FOUND:')
|
|
301
|
-
errors.forEach(err => console.log(` - ${err}`))
|
|
307
|
+
errors.forEach((err) => console.log(` - ${err}`))
|
|
302
308
|
console.log('\n❌ SSR Safety Test FAILED!')
|
|
303
309
|
if (warnings.length > 0) {
|
|
304
310
|
console.log(`\n⚠️ ${warnings.length} warning(s):`)
|
|
305
|
-
warnings.slice(0, 5).forEach(warn => console.log(` - ${warn}`))
|
|
311
|
+
warnings.slice(0, 5).forEach((warn) => console.log(` - ${warn}`))
|
|
306
312
|
}
|
|
307
313
|
process.exit(1)
|
|
308
314
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
2
2
|
import {
|
|
3
3
|
Manager,
|
|
4
4
|
SignerActionable,
|
|
@@ -522,12 +522,12 @@ describe('Transactions', () => {
|
|
|
522
522
|
})
|
|
523
523
|
|
|
524
524
|
let transactionsList: Transaction[] = []
|
|
525
|
-
let
|
|
525
|
+
let _updateCount = 0
|
|
526
526
|
|
|
527
527
|
// Use onTransactionsUpdate to verify list functionality
|
|
528
528
|
const unsubscribe = manager.transactions.onTransactionsUpdate((txs) => {
|
|
529
529
|
transactionsList = txs
|
|
530
|
-
|
|
530
|
+
_updateCount++
|
|
531
531
|
})
|
|
532
532
|
|
|
533
533
|
// Initially should be empty
|
package/test/wallets.test.ts
CHANGED
|
@@ -73,9 +73,9 @@ describe('Wallets', () => {
|
|
|
73
73
|
it('Should register and unregister wallet selector', async () => {
|
|
74
74
|
manager = newManager()
|
|
75
75
|
|
|
76
|
-
let
|
|
76
|
+
let _selectorCalls = 0
|
|
77
77
|
const mockSelector = async () => {
|
|
78
|
-
|
|
78
|
+
_selectorCalls++
|
|
79
79
|
return 'create-new' as const
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -160,7 +160,7 @@ describe('Wallets', () => {
|
|
|
160
160
|
const mnemonic = Mnemonic.random(Mnemonic.english)
|
|
161
161
|
|
|
162
162
|
// Create initial wallet
|
|
163
|
-
const
|
|
163
|
+
const _firstWallet = await manager!.wallets.signUp({
|
|
164
164
|
mnemonic,
|
|
165
165
|
kind: 'mnemonic',
|
|
166
166
|
noGuard: true,
|
|
@@ -705,8 +705,8 @@ describe('Wallets', () => {
|
|
|
705
705
|
|
|
706
706
|
it('Should trigger an update when a wallet is logged in', async () => {
|
|
707
707
|
const manager = newManager()
|
|
708
|
-
|
|
709
|
-
let wallet:
|
|
708
|
+
// eslint-disable-next-line
|
|
709
|
+
let wallet: Address.Address | undefined
|
|
710
710
|
|
|
711
711
|
let callbackCalls = 0
|
|
712
712
|
let unregisterCallback: (() => void) | undefined
|