@lukso/up-connector 0.4.0-dev.a8c9315

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 (109) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +280 -0
  3. package/dist/account-modal.cjs +9 -0
  4. package/dist/account-modal.cjs.map +1 -0
  5. package/dist/account-modal.d.cts +16 -0
  6. package/dist/account-modal.d.ts +16 -0
  7. package/dist/account-modal.js +9 -0
  8. package/dist/account-modal.js.map +1 -0
  9. package/dist/auto-setup.cjs +17 -0
  10. package/dist/auto-setup.cjs.map +1 -0
  11. package/dist/auto-setup.d.cts +123 -0
  12. package/dist/auto-setup.d.ts +123 -0
  13. package/dist/auto-setup.js +17 -0
  14. package/dist/auto-setup.js.map +1 -0
  15. package/dist/avatar-CmUCtW_w.d.cts +205 -0
  16. package/dist/avatar-CmUCtW_w.d.ts +205 -0
  17. package/dist/avatar.cjs +12 -0
  18. package/dist/avatar.cjs.map +1 -0
  19. package/dist/avatar.d.cts +1 -0
  20. package/dist/avatar.d.ts +1 -0
  21. package/dist/avatar.js +12 -0
  22. package/dist/avatar.js.map +1 -0
  23. package/dist/backup-modal.cjs +9 -0
  24. package/dist/backup-modal.cjs.map +1 -0
  25. package/dist/backup-modal.d.cts +41 -0
  26. package/dist/backup-modal.d.ts +41 -0
  27. package/dist/backup-modal.js +9 -0
  28. package/dist/backup-modal.js.map +1 -0
  29. package/dist/chunk-3SGSPHOZ.js +595 -0
  30. package/dist/chunk-3SGSPHOZ.js.map +1 -0
  31. package/dist/chunk-6AYZOIFY.js +181 -0
  32. package/dist/chunk-6AYZOIFY.js.map +1 -0
  33. package/dist/chunk-6N35TCFT.js +852 -0
  34. package/dist/chunk-6N35TCFT.js.map +1 -0
  35. package/dist/chunk-7ETKG6KR.cjs +387 -0
  36. package/dist/chunk-7ETKG6KR.cjs.map +1 -0
  37. package/dist/chunk-EUXUH3YW.js +15 -0
  38. package/dist/chunk-EUXUH3YW.js.map +1 -0
  39. package/dist/chunk-GFVUWAG4.cjs +158 -0
  40. package/dist/chunk-GFVUWAG4.cjs.map +1 -0
  41. package/dist/chunk-IAKQFHFD.cjs +595 -0
  42. package/dist/chunk-IAKQFHFD.cjs.map +1 -0
  43. package/dist/chunk-MH7MP7XK.cjs +181 -0
  44. package/dist/chunk-MH7MP7XK.cjs.map +1 -0
  45. package/dist/chunk-NWCNJSG3.js +387 -0
  46. package/dist/chunk-NWCNJSG3.js.map +1 -0
  47. package/dist/chunk-NXU2DQAV.js +1128 -0
  48. package/dist/chunk-NXU2DQAV.js.map +1 -0
  49. package/dist/chunk-ORJK2YGG.cjs +852 -0
  50. package/dist/chunk-ORJK2YGG.cjs.map +1 -0
  51. package/dist/chunk-RFA6SEIS.cjs +1128 -0
  52. package/dist/chunk-RFA6SEIS.cjs.map +1 -0
  53. package/dist/chunk-XGIT7YUY.js +31 -0
  54. package/dist/chunk-XGIT7YUY.js.map +1 -0
  55. package/dist/chunk-XOKG3KIL.cjs +31 -0
  56. package/dist/chunk-XOKG3KIL.cjs.map +1 -0
  57. package/dist/chunk-YIWSPI4I.js +158 -0
  58. package/dist/chunk-YIWSPI4I.js.map +1 -0
  59. package/dist/chunk-ZBDE64SD.cjs +15 -0
  60. package/dist/chunk-ZBDE64SD.cjs.map +1 -0
  61. package/dist/connect-modal/index.cjs +20 -0
  62. package/dist/connect-modal/index.cjs.map +1 -0
  63. package/dist/connect-modal/index.d.cts +9 -0
  64. package/dist/connect-modal/index.d.ts +9 -0
  65. package/dist/connect-modal/index.js +20 -0
  66. package/dist/connect-modal/index.js.map +1 -0
  67. package/dist/index-D2orHGFi.d.cts +8 -0
  68. package/dist/index-D2orHGFi.d.ts +8 -0
  69. package/dist/index.cjs +793 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.d.cts +189 -0
  72. package/dist/index.d.ts +189 -0
  73. package/dist/index.js +793 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/restore-modal.cjs +9 -0
  76. package/dist/restore-modal.cjs.map +1 -0
  77. package/dist/restore-modal.d.cts +68 -0
  78. package/dist/restore-modal.d.ts +68 -0
  79. package/dist/restore-modal.js +9 -0
  80. package/dist/restore-modal.js.map +1 -0
  81. package/dist/wagmi-CVuDs_0h.d.cts +386 -0
  82. package/dist/wagmi-CVuDs_0h.d.ts +386 -0
  83. package/package.json +158 -0
  84. package/src/account-modal.ts +142 -0
  85. package/src/auto-setup.ts +362 -0
  86. package/src/avatar.ts +1135 -0
  87. package/src/backup-modal.ts +439 -0
  88. package/src/connect-modal/components/connection-view.ts +398 -0
  89. package/src/connect-modal/components/eoa-connection-view.ts +408 -0
  90. package/src/connect-modal/components/qr-code-view.ts +71 -0
  91. package/src/connect-modal/connect-modal.base.ts +18 -0
  92. package/src/connect-modal/connect-modal.config.ts +27 -0
  93. package/src/connect-modal/connect-modal.templates.ts +21 -0
  94. package/src/connect-modal/connect-modal.ts +270 -0
  95. package/src/connect-modal/connect-modal.types.ts +104 -0
  96. package/src/connect-modal/images/up-cube-glass.png +0 -0
  97. package/src/connect-modal/index.ts +23 -0
  98. package/src/connect-modal/services/wagmi.ts +266 -0
  99. package/src/connect-modal/styles/styles.css +1 -0
  100. package/src/connect-modal/utils/walletConnectDeepLinkUrl.ts +43 -0
  101. package/src/connector.ts +544 -0
  102. package/src/index.ts +62 -0
  103. package/src/popup-instance.ts +537 -0
  104. package/src/restore-modal.ts +702 -0
  105. package/src/styles/index.ts +28 -0
  106. package/src/styles/styles.css +1 -0
  107. package/src/types/css-raw.d.ts +4 -0
  108. package/src/types/images.d.ts +4 -0
  109. package/src/types.ts +168 -0
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Backup Modal - Lit Component
3
+ *
4
+ * Framework-agnostic backup modal for wallet data export.
5
+ * Uses lukso-modal from @lukso/web-components for consistent UI.
6
+ */
7
+
8
+ import type { BackupFile } from '@lukso/passkey-auth'
9
+ import { downloadBackup } from '@lukso/passkey-auth'
10
+ import { html, nothing } from 'lit'
11
+ import { customElement, property, state } from 'lit/decorators.js'
12
+ import zxcvbn from 'zxcvbn'
13
+ import { CoreLitElement } from './styles'
14
+
15
+ // Import lukso web components
16
+ import '@lukso/web-components/dist/components/lukso-modal'
17
+ import '@lukso/web-components/dist/components/lukso-button'
18
+ import '@lukso/web-components/dist/components/lukso-input'
19
+
20
+ enum Step {
21
+ CHOICE = 1,
22
+ PASSWORD = 2,
23
+ DOWNLOAD = 3,
24
+ }
25
+
26
+ interface PasswordStrength {
27
+ level: string
28
+ label: string
29
+ color: string
30
+ bgColor: string
31
+ width: number
32
+ feedback: string
33
+ crackTime: string | number
34
+ }
35
+
36
+ @customElement('backup-modal')
37
+ export class BackupModal extends CoreLitElement {
38
+ // Public properties
39
+ @property({ type: Boolean, reflect: true }) open = false
40
+ @property({ type: String }) theme: 'light' | 'dark' | 'auto' = 'auto'
41
+
42
+ // Private state - wizard flow
43
+ @state() private currentStep: Step = Step.CHOICE
44
+ @state() private useEncryption = true
45
+ @state() private password = ''
46
+ @state() private passwordConfirm = ''
47
+ @state() private passwordErrors: string[] = []
48
+ @state() private isCreatingBackup = false
49
+ @state() private generatedBackup: BackupFile | null = null
50
+
51
+ /**
52
+ * Public method for parent to set backup result
53
+ * Called after parent handles the 'create' event
54
+ */
55
+ public setBackupResult(
56
+ backupFile: BackupFile | null,
57
+ options?: {
58
+ error?: string
59
+ }
60
+ ) {
61
+ this.isCreatingBackup = false
62
+
63
+ if (options?.error) {
64
+ this.passwordErrors = [options.error]
65
+ this.generatedBackup = null
66
+ } else if (backupFile) {
67
+ this.generatedBackup = backupFile
68
+ this.currentStep = Step.DOWNLOAD
69
+ }
70
+ }
71
+
72
+ render() {
73
+ return html`
74
+ <lukso-modal
75
+ ?is-open=${this.open}
76
+ size="medium"
77
+ @on-backdrop-click=${this.close}
78
+ >
79
+ <div class="p-6">
80
+ <!-- Header -->
81
+ <h2 class="m-0 mb-6 text-neutral-20 dark:text-white heading-inter-21-semi-bold">
82
+ ${this.getStepTitle()}
83
+ </h2>
84
+
85
+ <!-- Step content -->
86
+ ${this.renderStep()}
87
+ </div>
88
+ </lukso-modal>
89
+ `
90
+ }
91
+
92
+ private renderStep() {
93
+ switch (this.currentStep) {
94
+ case Step.CHOICE:
95
+ return this.renderChoiceStep()
96
+ case Step.PASSWORD:
97
+ return this.renderPasswordStep()
98
+ case Step.DOWNLOAD:
99
+ return this.renderDownloadStep()
100
+ default:
101
+ return nothing
102
+ }
103
+ }
104
+
105
+ private renderChoiceStep() {
106
+ return html`
107
+ <div class="flex flex-col gap-3 mb-6">
108
+ <!-- Encrypted option (recommended) -->
109
+ <div
110
+ class="border-2 border-neutral-90 dark:border-neutral-70 rounded-lg p-4 cursor-pointer transition-all hover:border-neutral-60 dark:hover:border-neutral-60"
111
+ @click=${() => this.selectBackupType(true)}
112
+ >
113
+ <div class="flex items-center gap-3 mb-2">
114
+ <span class="text-neutral-10 dark:text-white heading-inter-16-semi-bold flex-1">
115
+ Encrypt backup file
116
+ </span>
117
+ <span class="text-xs text-neutral-50 dark:text-neutral-60 uppercase tracking-wide">
118
+ Recommended
119
+ </span>
120
+ </div>
121
+ <p class="m-0 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular">
122
+ Uses password-based encryption to protect the secrets in this file.
123
+ </p>
124
+ </div>
125
+
126
+ <!-- Unencrypted option -->
127
+ <div
128
+ class="border-2 border-neutral-90 dark:border-neutral-70 rounded-lg p-4 cursor-pointer transition-all hover:border-neutral-60 dark:hover:border-neutral-60"
129
+ @click=${() => this.selectBackupType(false)}
130
+ >
131
+ <div class="flex items-center gap-3 mb-2">
132
+ <span class="text-neutral-10 dark:text-white heading-inter-16-semi-bold flex-1">
133
+ Plain text backup
134
+ </span>
135
+ <span class="text-xs text-neutral-50 dark:text-neutral-60 uppercase tracking-wide">
136
+ For development only
137
+ </span>
138
+ </div>
139
+ <p class="m-0 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular">
140
+ Secrets will be stored in plain text.
141
+ </p>
142
+ </div>
143
+ </div>
144
+
145
+ <div class="flex justify-between gap-3">
146
+ <lukso-button variant="text" @click=${this.close}>
147
+ Cancel
148
+ </lukso-button>
149
+ </div>
150
+ `
151
+ }
152
+
153
+ private renderPasswordStep() {
154
+ const passwordStrength = this.password
155
+ ? this.calculatePasswordStrength()
156
+ : null
157
+ const passwordsMatch =
158
+ this.password &&
159
+ this.passwordConfirm &&
160
+ this.password === this.passwordConfirm
161
+ const canProceed = this.password && this.passwordConfirm && passwordsMatch
162
+
163
+ return html`
164
+ <p class="mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-16-regular">
165
+ Choose a strong password to encrypt your backup. You'll need this password to restore your wallet.
166
+ </p>
167
+
168
+ <div class="space-y-4">
169
+ <lukso-input
170
+ type="password"
171
+ label="Password"
172
+ placeholder="Enter a strong password"
173
+ .value=${this.password}
174
+ @on-input=${(e: CustomEvent) => (this.password = e.detail.value)}
175
+ is-full-width
176
+ autofocus
177
+ ></lukso-input>
178
+
179
+ ${this.passwordErrors.map(
180
+ (error) => html`
181
+ <div class="mt-1 text-red-55 paragraph-inter-13-regular">${error}</div>
182
+ `
183
+ )}
184
+
185
+ ${
186
+ passwordStrength
187
+ ? html`
188
+ <div class="mt-3">
189
+ <div class="flex items-center justify-between mb-1">
190
+ <span class="paragraph-inter-13-regular text-neutral-40">Password strength:</span>
191
+ <span class="paragraph-inter-13-semi-bold ${passwordStrength.color}">${passwordStrength.label}</span>
192
+ </div>
193
+ <div class="h-1.5 bg-neutral-90 dark:bg-neutral-70 rounded-full overflow-hidden">
194
+ <div
195
+ class="h-full ${passwordStrength.bgColor} transition-all duration-300"
196
+ style="width: ${passwordStrength.width}%"
197
+ ></div>
198
+ </div>
199
+ <p class="mt-1 mb-0 text-neutral-40 paragraph-inter-12-regular">
200
+ Time to crack: ${passwordStrength.crackTime}
201
+ </p>
202
+ ${
203
+ passwordStrength.feedback
204
+ ? html`
205
+ <p class="mt-2 mb-0 text-neutral-40 paragraph-inter-12-regular">${passwordStrength.feedback}</p>
206
+ `
207
+ : nothing
208
+ }
209
+ </div>
210
+ `
211
+ : nothing
212
+ }
213
+
214
+ <lukso-input
215
+ type="password"
216
+ label="Confirm Password"
217
+ placeholder="Re-enter your password"
218
+ .value=${this.passwordConfirm}
219
+ @on-input=${(e: CustomEvent) => (this.passwordConfirm = e.detail.value)}
220
+ is-full-width
221
+ ></lukso-input>
222
+
223
+ ${
224
+ this.passwordConfirm
225
+ ? html`
226
+ <div class="flex items-center justify-between mt-2">
227
+ <span class="paragraph-inter-13-regular text-neutral-40">Passwords match:</span>
228
+ <span class="paragraph-inter-13-semi-bold ${passwordsMatch ? 'text-green-54' : 'text-red-55'}">
229
+ ${passwordsMatch ? 'Yes' : 'No'}
230
+ </span>
231
+ </div>
232
+ `
233
+ : nothing
234
+ }
235
+ </div>
236
+
237
+ <div class="flex justify-between gap-3 mt-6">
238
+ <div class="flex gap-3">
239
+ <lukso-button variant="text" @click=${this.close}>
240
+ Cancel
241
+ </lukso-button>
242
+ <lukso-button variant="secondary" @click=${this.goBack}>
243
+ Back
244
+ </lukso-button>
245
+ </div>
246
+ <lukso-button
247
+ variant="primary"
248
+ ?disabled=${!canProceed || this.isCreatingBackup}
249
+ ?is-loading=${this.isCreatingBackup}
250
+ @click=${this.createBackup}
251
+ >
252
+ Create Backup
253
+ </lukso-button>
254
+ </div>
255
+ `
256
+ }
257
+
258
+ private renderDownloadStep() {
259
+ return html`
260
+ <p class="mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-16-regular">
261
+ Your backup has been created${this.useEncryption ? ' and encrypted' : ''}. Download it and keep it in a safe place.
262
+ </p>
263
+
264
+ ${
265
+ !this.useEncryption
266
+ ? html`
267
+ <p class="mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular">
268
+ This unencrypted backup is intended for development purposes. Use it when creating dapps that need access to the profile for testing.
269
+ </p>
270
+ `
271
+ : nothing
272
+ }
273
+
274
+ <div class="flex justify-end gap-3">
275
+ <lukso-button variant="primary" @click=${this.handleDownload}>
276
+ Download Backup
277
+ </lukso-button>
278
+ </div>
279
+ `
280
+ }
281
+
282
+ private getStepTitle(): string {
283
+ switch (this.currentStep) {
284
+ case Step.CHOICE:
285
+ return 'Backup Wallet'
286
+ case Step.PASSWORD:
287
+ return 'Set Password'
288
+ case Step.DOWNLOAD:
289
+ return 'Download Backup'
290
+ default:
291
+ return 'Backup Wallet'
292
+ }
293
+ }
294
+
295
+ private selectBackupType(encrypted: boolean) {
296
+ this.useEncryption = encrypted
297
+ if (encrypted) {
298
+ this.currentStep = Step.PASSWORD
299
+ } else {
300
+ // Unencrypted backup - create immediately
301
+ this.createBackup()
302
+ }
303
+ }
304
+
305
+ private async createBackup() {
306
+ this.isCreatingBackup = true
307
+ this.passwordErrors = []
308
+
309
+ // Emit create event with password (if encrypted)
310
+ // Parent should handle backup creation
311
+ const createEvent = new CustomEvent('create', {
312
+ detail: {
313
+ password: this.useEncryption ? this.password : undefined,
314
+ encrypted: this.useEncryption,
315
+ },
316
+ bubbles: true,
317
+ composed: true,
318
+ cancelable: true,
319
+ })
320
+
321
+ this.dispatchEvent(createEvent)
322
+
323
+ // If parent didn't prevent default, show error
324
+ if (!createEvent.defaultPrevented) {
325
+ this.passwordErrors = [
326
+ 'No backup handler configured. Please handle the "create" event.',
327
+ ]
328
+ this.isCreatingBackup = false
329
+ }
330
+ // Otherwise, parent will call setBackupResult()
331
+ }
332
+
333
+ private handleDownload() {
334
+ if (this.generatedBackup) {
335
+ downloadBackup(this.generatedBackup)
336
+
337
+ // Dispatch download event
338
+ this.dispatchEvent(
339
+ new CustomEvent('download', {
340
+ detail: this.generatedBackup,
341
+ bubbles: true,
342
+ composed: true,
343
+ })
344
+ )
345
+
346
+ // Close modal after download
347
+ setTimeout(() => {
348
+ this.close()
349
+ }, 100)
350
+ }
351
+ }
352
+
353
+ private goBack() {
354
+ if (this.currentStep === Step.PASSWORD) {
355
+ this.currentStep = Step.CHOICE
356
+ this.password = ''
357
+ this.passwordConfirm = ''
358
+ this.passwordErrors = []
359
+ }
360
+ }
361
+
362
+ private close() {
363
+ this.open = false
364
+ this.dispatchEvent(
365
+ new CustomEvent('close', { bubbles: true, composed: true })
366
+ )
367
+
368
+ // Reset state after animation
369
+ setTimeout(() => {
370
+ this.currentStep = Step.CHOICE
371
+ this.useEncryption = true
372
+ this.password = ''
373
+ this.passwordConfirm = ''
374
+ this.passwordErrors = []
375
+ this.isCreatingBackup = false
376
+ this.generatedBackup = null
377
+ }, 300)
378
+ }
379
+
380
+ private calculatePasswordStrength(): PasswordStrength {
381
+ const result = zxcvbn(this.password)
382
+
383
+ const strengthMap = [
384
+ {
385
+ level: 'very-weak',
386
+ label: 'Very Weak',
387
+ color: 'text-red-55',
388
+ bgColor: 'bg-red-55',
389
+ width: 20,
390
+ },
391
+ {
392
+ level: 'weak',
393
+ label: 'Weak',
394
+ color: 'text-red-65',
395
+ bgColor: 'bg-red-65',
396
+ width: 40,
397
+ },
398
+ {
399
+ level: 'fair',
400
+ label: 'Fair',
401
+ color: 'text-yellow-55',
402
+ bgColor: 'bg-yellow-55',
403
+ width: 60,
404
+ },
405
+ {
406
+ level: 'good',
407
+ label: 'Good',
408
+ color: 'text-green-54',
409
+ bgColor: 'bg-green-54',
410
+ width: 80,
411
+ },
412
+ {
413
+ level: 'strong',
414
+ label: 'Strong',
415
+ color: 'text-green-45',
416
+ bgColor: 'bg-green-45',
417
+ width: 100,
418
+ },
419
+ ]
420
+
421
+ const strength = strengthMap[result.score]
422
+ const feedback =
423
+ result.feedback.suggestions.join(' ') || result.feedback.warning || ''
424
+ const crackTime =
425
+ result.crack_times_display.offline_slow_hashing_1e4_per_second
426
+
427
+ return {
428
+ ...strength,
429
+ feedback,
430
+ crackTime,
431
+ }
432
+ }
433
+ }
434
+
435
+ declare global {
436
+ interface HTMLElementTagNameMap {
437
+ 'backup-modal': BackupModal
438
+ }
439
+ }