wallet-connect-button-vue 1.0.11 → 1.0.13
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/dist/index.esm.js +173 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +173 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -40,6 +40,7 @@ const _hoisted_2 = {
|
|
|
40
40
|
const _hoisted_3 = { class: "verification-card" };
|
|
41
41
|
const _hoisted_4 = ["text", "usecase", "start-url", "lang", "help-base-url", "same-device-ul", "cross-device-ul"];
|
|
42
42
|
|
|
43
|
+
// Types for credentials functionality
|
|
43
44
|
|
|
44
45
|
const _sfc_main = {
|
|
45
46
|
__name: 'WalletConnectButton',
|
|
@@ -48,13 +49,16 @@ const _sfc_main = {
|
|
|
48
49
|
clientId: { type: String, required: true },
|
|
49
50
|
onSuccess: { type: Function, required: false },
|
|
50
51
|
apiKey: { type: String, required: false },
|
|
51
|
-
|
|
52
|
+
useLocalWcServer: { type: Boolean, required: false, default: false },
|
|
53
|
+
business: { type: Boolean, required: false, default: false },
|
|
52
54
|
lang: { type: String, required: false, default: 'nl' },
|
|
53
55
|
helpBaseUrl: { type: String, required: false },
|
|
54
56
|
issuance: { type: Boolean, required: false }
|
|
55
57
|
},
|
|
56
58
|
setup(__props) {
|
|
57
59
|
|
|
60
|
+
const credentialsCache = new Map();
|
|
61
|
+
|
|
58
62
|
const props = __props;
|
|
59
63
|
|
|
60
64
|
const { searchParams, setSearchParams, removeSearchParam } = useSearchParams();
|
|
@@ -62,23 +66,183 @@ const loading = ref(false);
|
|
|
62
66
|
const error = ref(null);
|
|
63
67
|
const buttonRef = ref(null);
|
|
64
68
|
|
|
69
|
+
const getDefaultHost = () => {
|
|
70
|
+
// If useLocalWcServer is set, use local server
|
|
71
|
+
if (props.useLocalWcServer) {
|
|
72
|
+
if (props.business) {
|
|
73
|
+
return props.issuance ? 'http://localhost:4007' : 'http://bw.localhost:3021';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return props.issuance ? 'http://localhost:3007' : 'http://localhost:3021';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Otherwise use remote servers
|
|
80
|
+
if (props.business) {
|
|
81
|
+
return props.issuance ? 'https://bw.issuance.wallet-connect.eu' : 'https://bw.wallet-connect.eu';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return props.issuance ? 'https://issuance.wallet-connect.eu' : 'https://wallet-connect.eu';
|
|
85
|
+
};
|
|
86
|
+
|
|
65
87
|
const startUrl = computed(() => {
|
|
66
|
-
const baseUrl =
|
|
88
|
+
const baseUrl = getDefaultHost();
|
|
67
89
|
const returnUrl = typeof window !== 'undefined' ? window.location.href : '';
|
|
68
90
|
return `${baseUrl}/api/create-session?lang=en&return_url=${encodeURIComponent(returnUrl)}`;
|
|
69
91
|
});
|
|
70
92
|
|
|
71
93
|
const constructURI = (session_type) => {
|
|
72
|
-
const request_uri =
|
|
94
|
+
const request_uri = `${getDefaultHost()}/disclosure/${props.clientId}/request_uri?session_type=${session_type}`;
|
|
73
95
|
const request_uri_method = "post";
|
|
74
96
|
const client_id_uri = `${props.clientId}.example.com`;
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
|
|
98
|
+
const deepLinkScheme = props.business
|
|
99
|
+
? 'businesswalletdebuginteraction://wallet.kvk.rijksoverheid.nl'
|
|
100
|
+
: 'walletdebuginteraction://wallet.edi.rijksoverheid.nl';
|
|
101
|
+
|
|
102
|
+
return `${deepLinkScheme}/disclosure_based_issuance?request_uri=${encodeURIComponent(
|
|
103
|
+
request_uri
|
|
104
|
+
)}&request_uri_method=${request_uri_method}&client_id=${client_id_uri}`;
|
|
77
105
|
};
|
|
78
106
|
|
|
79
107
|
const sameDeviceUl = computed(() => constructURI("same_device"));
|
|
80
108
|
const crossDeviceUl = computed(() => constructURI("cross_device"));
|
|
81
109
|
|
|
110
|
+
const fetchRequestedCredentials = async () => {
|
|
111
|
+
if (!props.apiKey || !props.clientId) return [];
|
|
112
|
+
|
|
113
|
+
const cacheKey = `${props.clientId}-${getDefaultHost()}`;
|
|
114
|
+
|
|
115
|
+
// Check if we already have data in cache
|
|
116
|
+
const cached = credentialsCache.get(cacheKey);
|
|
117
|
+
if (cached?.data) {
|
|
118
|
+
return cached.data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check if there's already a request in progress
|
|
122
|
+
if (cached?.promise) {
|
|
123
|
+
return await cached.promise;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const fetchPromise = (async () => {
|
|
127
|
+
try {
|
|
128
|
+
const baseUrl = getDefaultHost();
|
|
129
|
+
const url = `${baseUrl}/api/client/${props.clientId}/requested-credentials`;
|
|
130
|
+
const headers = { 'Authorization': `Bearer ${props.apiKey}` };
|
|
131
|
+
|
|
132
|
+
const response = await axios.get(url, { headers });
|
|
133
|
+
|
|
134
|
+
// Extract credentials from the response
|
|
135
|
+
const credentials = response.data?.data?.requestedCredentials || [];
|
|
136
|
+
|
|
137
|
+
// Cache the result
|
|
138
|
+
credentialsCache.set(cacheKey, { data: credentials });
|
|
139
|
+
return credentials;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
// Remove failed request from cache
|
|
142
|
+
credentialsCache.delete(cacheKey);
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
})();
|
|
146
|
+
|
|
147
|
+
// Cache the promise to prevent duplicate requests
|
|
148
|
+
credentialsCache.set(cacheKey, { promise: fetchPromise });
|
|
149
|
+
|
|
150
|
+
return await fetchPromise;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const injectCredentialsIntoShadowDOM = (credentials, retryCount = 0) => {
|
|
154
|
+
const maxRetries = 10;
|
|
155
|
+
const walletButton = buttonRef.value;
|
|
156
|
+
|
|
157
|
+
if (!walletButton || !walletButton.shadowRoot) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Remove any existing credential info
|
|
162
|
+
const existingCredentials = walletButton.shadowRoot.querySelector('.required-credentials');
|
|
163
|
+
if (existingCredentials) {
|
|
164
|
+
existingCredentials.remove();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (credentials.length === 0) return;
|
|
168
|
+
|
|
169
|
+
// Look for the modal and website section
|
|
170
|
+
const modal = walletButton.shadowRoot.querySelector('.modal');
|
|
171
|
+
if (!modal) {
|
|
172
|
+
// Retry if modal not found yet
|
|
173
|
+
if (retryCount < maxRetries) {
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
injectCredentialsIntoShadowDOM(credentials, retryCount + 1);
|
|
176
|
+
}, 200);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const websiteSection = modal.querySelector('.website');
|
|
183
|
+
|
|
184
|
+
// Determine language and translations
|
|
185
|
+
const isNL = props.lang === 'nl';
|
|
186
|
+
const headerText = isNL ? 'Benodigde Attestaties:' : 'Required Credentials:';
|
|
187
|
+
const getLinkText = isNL ? '→ Verkrijg attestatie' : '→ Get credential';
|
|
188
|
+
|
|
189
|
+
// Create credential info element
|
|
190
|
+
const credentialsDiv = document.createElement('div');
|
|
191
|
+
credentialsDiv.className = 'required-credentials';
|
|
192
|
+
credentialsDiv.innerHTML = `
|
|
193
|
+
<div style="
|
|
194
|
+
background: #f8f9fa;
|
|
195
|
+
border: 1px solid #e9ecef;
|
|
196
|
+
border-radius: 6px;
|
|
197
|
+
padding: 12px;
|
|
198
|
+
font-family: inherit;
|
|
199
|
+
font-size: 13px;
|
|
200
|
+
line-height: 1.4;
|
|
201
|
+
">
|
|
202
|
+
<div style="margin: 0 0 8px 0; color: #212529; font-size: 14px; font-weight: 600;">${headerText}</div>
|
|
203
|
+
${credentials.map(credential => {
|
|
204
|
+
const credentialName = isNL ? credential.credentialName.nl : credential.credentialName.en;
|
|
205
|
+
return `
|
|
206
|
+
<div style="margin-bottom: 6px; display: flex; align-items: center; flex-wrap: wrap; gap: 8px;">
|
|
207
|
+
<span style="color: #495057; font-weight: 500;">${credentialName}</span>
|
|
208
|
+
${credential.websiteUrl ? `
|
|
209
|
+
<a href="${credential.websiteUrl}" target="_blank" rel="noopener noreferrer" style="
|
|
210
|
+
color: #0066cc;
|
|
211
|
+
text-decoration: none;
|
|
212
|
+
font-size: 12px;
|
|
213
|
+
white-space: nowrap;
|
|
214
|
+
">${getLinkText}</a>
|
|
215
|
+
` : ''}
|
|
216
|
+
</div>
|
|
217
|
+
`;
|
|
218
|
+
}).join('')}
|
|
219
|
+
</div>
|
|
220
|
+
`;
|
|
221
|
+
|
|
222
|
+
// Insert the credentials div after the website section
|
|
223
|
+
if (websiteSection) {
|
|
224
|
+
websiteSection.insertAdjacentElement('afterend', credentialsDiv);
|
|
225
|
+
} else {
|
|
226
|
+
// Fallback: insert at the beginning of modal
|
|
227
|
+
modal.insertBefore(credentialsDiv, modal.firstChild);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const handleButtonClick = async (_event) => {
|
|
232
|
+
try {
|
|
233
|
+
const credentials = await fetchRequestedCredentials();
|
|
234
|
+
|
|
235
|
+
if (credentials && credentials.length > 0) {
|
|
236
|
+
// Inject credentials into the shadow DOM with multiple attempts
|
|
237
|
+
setTimeout(() => {
|
|
238
|
+
injectCredentialsIntoShadowDOM(credentials);
|
|
239
|
+
}, 100);
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error('Failed to fetch credentials:', error);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
82
246
|
const handleSuccess = (e) => {
|
|
83
247
|
const customEvent = e;
|
|
84
248
|
if (customEvent.detail && customEvent.detail.length > 1) {
|
|
@@ -105,6 +269,7 @@ const loadWebComponent = async () => {
|
|
|
105
269
|
if (button) {
|
|
106
270
|
button.addEventListener("success", handleSuccess);
|
|
107
271
|
button.addEventListener("failed", handleFailed);
|
|
272
|
+
button.addEventListener("click", handleButtonClick);
|
|
108
273
|
}
|
|
109
274
|
} catch (error) {
|
|
110
275
|
console.warn('Could not load nl-wallet-web.js:', error);
|
|
@@ -118,12 +283,12 @@ const fetchDisclosedAttributes = async () => {
|
|
|
118
283
|
if (!session_token) return;
|
|
119
284
|
|
|
120
285
|
loading.value = true;
|
|
121
|
-
const baseUrl = props.apiKey ? (
|
|
286
|
+
const baseUrl = props.apiKey ? getDefaultHost() : "";
|
|
122
287
|
let url = baseUrl + `/api/disclosed-attributes?session_token=${session_token}&client_id=${props.clientId}`;
|
|
123
288
|
if (nonce) url = `${url}&nonce=${nonce}`;
|
|
124
289
|
|
|
125
290
|
const headers = props.apiKey ? { 'Authorization': `Bearer ${props.apiKey}` } : {};
|
|
126
|
-
|
|
291
|
+
|
|
127
292
|
try {
|
|
128
293
|
const { data } = await axios.get(url, { headers });
|
|
129
294
|
console.log("Disclosed attributes:", data);
|
|
@@ -152,6 +317,7 @@ onUnmounted(() => {
|
|
|
152
317
|
if (button) {
|
|
153
318
|
button.removeEventListener("success", handleSuccess);
|
|
154
319
|
button.removeEventListener("failed", handleFailed);
|
|
320
|
+
button.removeEventListener("click", handleButtonClick);
|
|
155
321
|
}
|
|
156
322
|
});
|
|
157
323
|
|