@eudiplo/sdk-core 1.14.0-main.070d9f8

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/README.md ADDED
@@ -0,0 +1,460 @@
1
+ # @eudiplo/sdk-core
2
+
3
+ Framework-agnostic EUDIPLO SDK for demos and integrations. Works with Node.js, browsers, React, Vue, vanilla JS, and any other JavaScript environment.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @eudiplo/sdk-core
9
+ # or
10
+ pnpm add @eudiplo/sdk-core
11
+ # or
12
+ yarn add @eudiplo/sdk-core
13
+ ```
14
+
15
+ ## Quick Start - The Simplest Way
16
+
17
+ ### One-liner for Age Verification
18
+
19
+ ```typescript
20
+ import { verifyAndWait } from '@eudiplo/sdk-core';
21
+
22
+ const session = await verifyAndWait({
23
+ baseUrl: 'https://eudiplo.example.com',
24
+ clientId: 'my-demo',
25
+ clientSecret: 'secret',
26
+ configId: 'age-over-18',
27
+ onUri: (uri) => showQRCode(uri), // Your QR code display function
28
+ onUpdate: (s) => console.log('Status:', s.status),
29
+ });
30
+
31
+ console.log('Verified!', session.credentials);
32
+ ```
33
+
34
+ ### Two-step Flow (More Control)
35
+
36
+ ```typescript
37
+ import { verify } from '@eudiplo/sdk-core';
38
+
39
+ // Step 1: Create the request
40
+ const { uri, sessionId, waitForCompletion } = await verify({
41
+ baseUrl: 'https://eudiplo.example.com',
42
+ clientId: 'my-demo',
43
+ clientSecret: 'secret',
44
+ configId: 'age-over-18',
45
+ });
46
+
47
+ // Step 2: Show QR code
48
+ showQRCode(uri);
49
+
50
+ // Step 3: Wait for user to scan and respond
51
+ const session = await waitForCompletion();
52
+ console.log('Verified credentials:', session.credentials);
53
+ ```
54
+
55
+ ### Credential Issuance
56
+
57
+ ```typescript
58
+ import { issue } from '@eudiplo/sdk-core';
59
+
60
+ const { uri, waitForCompletion } = await issue({
61
+ baseUrl: 'https://eudiplo.example.com',
62
+ clientId: 'my-demo',
63
+ clientSecret: 'secret',
64
+ credentialConfigurationIds: ['PID'],
65
+ claims: {
66
+ PID: { given_name: 'John', family_name: 'Doe', birthdate: '1990-01-15' },
67
+ },
68
+ });
69
+
70
+ showQRCode(uri);
71
+ await waitForCompletion();
72
+ ```
73
+
74
+ ## Full API
75
+
76
+ ### Factory Functions (Easiest)
77
+
78
+ | Function | Description |
79
+ | ------------------------ | ----------------------------------------------------------------------------------------- |
80
+ | `verify(options)` | Create a presentation request, returns `{ uri, sessionId, waitForCompletion, getStatus }` |
81
+ | `issue(options)` | Create an issuance offer, returns `{ uri, sessionId, waitForCompletion, getStatus }` |
82
+ | `verifyAndWait(options)` | One-liner: create request + wait for result |
83
+ | `issueAndWait(options)` | One-liner: create offer + wait for result |
84
+
85
+ ### Digital Credentials API (Browser Native)
86
+
87
+ The SDK includes utilities for the [Digital Credentials API](https://wicg.github.io/digital-credentials/), enabling browser-native credential presentation without QR codes.
88
+
89
+ ```typescript
90
+ import { isDcApiAvailable, verifyWithDcApi } from '@eudiplo/sdk-core';
91
+
92
+ // Check if browser supports DC API
93
+ if (isDcApiAvailable()) {
94
+ const result = await verifyWithDcApi({
95
+ baseUrl: 'https://eudiplo.example.com',
96
+ clientId: 'my-demo',
97
+ clientSecret: 'secret',
98
+ configId: 'age-over-18',
99
+ });
100
+
101
+ console.log('Verified!', result.session.credentials);
102
+ } else {
103
+ // Fall back to QR code flow
104
+ const session = await verifyAndWait({...});
105
+ }
106
+ ```
107
+
108
+ #### DC API Functions
109
+
110
+ | Function | Description |
111
+ | ---------------------- | --------------------------------------------------- |
112
+ | `isDcApiAvailable()` | Check if browser supports Digital Credentials API |
113
+ | `verifyWithDcApi()` | Complete verification flow using browser-native API |
114
+ | `createDcApiRequest()` | Create a `DigitalCredentialRequestOptions` object |
115
+
116
+ #### Lower-level DC API Usage
117
+
118
+ ```typescript
119
+ import { createDcApiRequest, EudiploClient } from '@eudiplo/sdk-core';
120
+
121
+ const client = new EudiploClient({...});
122
+
123
+ // Create presentation request
124
+ const { uri, sessionId } = await client.createPresentationRequest({
125
+ configId: 'age-over-18',
126
+ responseType: 'dc-api',
127
+ });
128
+
129
+ // Create the browser request object
130
+ const request = createDcApiRequest(uri);
131
+
132
+ // Call the browser API directly
133
+ const credential = await navigator.credentials.get(request);
134
+
135
+ // Submit the response and get verified session
136
+ const session = await client.submitDcApiResponse(sessionId, credential);
137
+ ```
138
+
139
+ #### Secure Server/Client Deployment (Recommended for Production)
140
+
141
+ When deploying to production, you should **never expose your client credentials to the browser**. The SDK provides helper functions to split the DC API flow between your server (where credentials are safe) and the browser (where the DC API runs).
142
+
143
+ **Server-side Functions:**
144
+
145
+ | Function | Description |
146
+ | -------------------------------- | ------------------------------------------------------ |
147
+ | `createDcApiRequestForBrowser()` | Create request on server, return safe data for browser |
148
+ | `submitDcApiWalletResponse()` | Submit wallet response to EUDIPLO from server |
149
+
150
+ **Browser-side Functions:**
151
+
152
+ | Function | Description |
153
+ | ------------- | ------------------------------------------------------ |
154
+ | `callDcApi()` | Call the native DC API with a request from your server |
155
+
156
+ ##### Example: Express.js Backend + Browser Frontend
157
+
158
+ **Server (Express.js / Next.js API route):**
159
+
160
+ ```typescript
161
+ import {
162
+ createDcApiRequestForBrowser,
163
+ submitDcApiWalletResponse,
164
+ } from '@eudiplo/sdk-core';
165
+
166
+ // POST /api/start-verification
167
+ app.post('/api/start-verification', async (req, res) => {
168
+ const requestData = await createDcApiRequestForBrowser({
169
+ baseUrl: process.env.EUDIPLO_URL,
170
+ clientId: process.env.EUDIPLO_CLIENT_ID, // ✅ Safe on server
171
+ clientSecret: process.env.EUDIPLO_SECRET, // ✅ Safe on server
172
+ configId: 'age-over-18',
173
+ });
174
+
175
+ // Only safe data is sent to browser (no secrets)
176
+ res.json(requestData);
177
+ });
178
+
179
+ // POST /api/complete-verification
180
+ app.post('/api/complete-verification', async (req, res) => {
181
+ const { responseUri, walletResponse } = req.body;
182
+
183
+ const result = await submitDcApiWalletResponse({
184
+ responseUri,
185
+ walletResponse,
186
+ sendResponse: true, // Get verified claims back
187
+ });
188
+
189
+ // result.credentials contains the verified data
190
+ res.json(result);
191
+ });
192
+ ```
193
+
194
+ **Browser (React / vanilla JS):**
195
+
196
+ ```typescript
197
+ import { callDcApi, isDcApiAvailable } from '@eudiplo/sdk-core';
198
+
199
+ async function verifyAge() {
200
+ // 1. Get the request from your server (credentials stay on server)
201
+ const requestData = await fetch('/api/start-verification', {
202
+ method: 'POST',
203
+ }).then((r) => r.json());
204
+
205
+ // 2. Check DC API support and call it locally
206
+ if (!isDcApiAvailable()) {
207
+ throw new Error('Digital Credentials API not supported');
208
+ }
209
+
210
+ const walletResponse = await callDcApi(requestData.requestObject);
211
+
212
+ // 3. Send the wallet response back to your server for verification
213
+ const result = await fetch('/api/complete-verification', {
214
+ method: 'POST',
215
+ headers: { 'Content-Type': 'application/json' },
216
+ body: JSON.stringify({
217
+ responseUri: requestData.responseUri,
218
+ walletResponse,
219
+ }),
220
+ }).then((r) => r.json());
221
+
222
+ console.log('Verified!', result.credentials);
223
+ return result;
224
+ }
225
+ ```
226
+
227
+ **What stays where:**
228
+
229
+ | Data | Location | Safe to expose? |
230
+ | ------------------------------ | ---------------- | ------------------- |
231
+ | `clientId` / `clientSecret` | Server only | ❌ Never expose |
232
+ | `requestObject` (signed JWT) | Server → Browser | ✅ Yes |
233
+ | `responseUri` | Server → Browser | ✅ Yes |
234
+ | Wallet response (encrypted VP) | Browser → Server | ✅ Yes |
235
+ | Verified credentials | Server only | Depends on use case |
236
+
237
+ ### Class-based API (More Control)
238
+
239
+ ```typescript
240
+ import { EudiploClient } from '@eudiplo/sdk-core';
241
+
242
+ const client = new EudiploClient({
243
+ baseUrl: 'https://eudiplo.example.com',
244
+ clientId: 'my-demo-client',
245
+ clientSecret: 'your-secret',
246
+ });
247
+
248
+ // Create a presentation request (e.g., for age verification)
249
+ const { uri, sessionId } = await client.createPresentationRequest({
250
+ configId: 'age-over-18',
251
+ });
252
+
253
+ console.log('Show this QR code:', uri);
254
+
255
+ // Wait for the user to scan and respond
256
+ const session = await client.waitForSession(sessionId, {
257
+ onUpdate: (s) => console.log('Status:', s.status),
258
+ });
259
+
260
+ console.log('Verified credentials:', session.credentials);
261
+ ```
262
+
263
+ ## API
264
+
265
+ ### `new EudiploClient(config)`
266
+
267
+ Create a new client instance.
268
+
269
+ ```typescript
270
+ const client = new EudiploClient({
271
+ baseUrl: 'https://eudiplo.example.com', // EUDIPLO server URL
272
+ clientId: 'my-client', // OAuth2 client ID
273
+ clientSecret: 'secret', // OAuth2 client secret
274
+ autoRefresh: true, // Auto-refresh tokens (default: true)
275
+ });
276
+ ```
277
+
278
+ ### `createPresentationRequest(options)`
279
+
280
+ Create a presentation request for credential verification.
281
+
282
+ ```typescript
283
+ const { uri, sessionId } = await client.createPresentationRequest({
284
+ configId: 'age-over-18', // Presentation config ID
285
+ responseType: 'uri', // 'uri' | 'qrcode' | 'dc-api'
286
+ redirectUri: 'https://...', // Optional redirect after completion
287
+ });
288
+ ```
289
+
290
+ ### `createIssuanceOffer(options)`
291
+
292
+ Create a credential issuance offer.
293
+
294
+ ```typescript
295
+ const { uri, sessionId } = await client.createIssuanceOffer({
296
+ credentialConfigurationIds: ['PID', 'mDL'],
297
+ claims: {
298
+ PID: { given_name: 'John', family_name: 'Doe' },
299
+ mDL: { driving_privileges: [...] }
300
+ },
301
+ flow: 'pre_authorized_code', // or 'authorization_code'
302
+ txCode: '1234' // Optional transaction code
303
+ });
304
+ ```
305
+
306
+ ### `getSession(sessionId)`
307
+
308
+ Get the current state of a session.
309
+
310
+ ```typescript
311
+ const session = await client.getSession(sessionId);
312
+ console.log(session.status); // 'active' | 'fetched' | 'completed' | 'expired' | 'failed'
313
+ ```
314
+
315
+ ### `waitForSession(sessionId, options)`
316
+
317
+ Poll until a session completes or fails.
318
+
319
+ ```typescript
320
+ const session = await client.waitForSession(sessionId, {
321
+ interval: 1000, // Poll every 1 second
322
+ timeout: 60000, // Timeout after 60 seconds
323
+ signal: abortController.signal, // Optional abort signal
324
+ onUpdate: (session) => {
325
+ console.log('Status:', session.status);
326
+ },
327
+ });
328
+ ```
329
+
330
+ ### `subscribeToSession(sessionId, options)`
331
+
332
+ Subscribe to real-time session status updates via Server-Sent Events (SSE).
333
+ This is more efficient than polling and provides instant updates.
334
+
335
+ ```typescript
336
+ const subscription = await client.subscribeToSession(sessionId, {
337
+ onStatusChange: (event) => {
338
+ console.log(`Status: ${event.status}`);
339
+ if (['completed', 'expired', 'failed'].includes(event.status)) {
340
+ subscription.close();
341
+ }
342
+ },
343
+ onError: (error) => console.error('SSE error:', error),
344
+ onOpen: () => console.log('Connected'),
345
+ });
346
+
347
+ // Later, to close the connection:
348
+ subscription.close();
349
+ ```
350
+
351
+ ### `waitForSessionWithSse(sessionId, options)`
352
+
353
+ Wait for session completion using SSE instead of polling. Returns a Promise
354
+ that resolves when the session completes.
355
+
356
+ ```typescript
357
+ try {
358
+ const finalStatus = await client.waitForSessionWithSse(sessionId, {
359
+ onStatusChange: (event) => console.log('Status:', event.status),
360
+ });
361
+ console.log('Session completed:', finalStatus);
362
+ } catch (error) {
363
+ console.error('Session failed:', error);
364
+ }
365
+ ```
366
+
367
+ ## Examples
368
+
369
+ ### Age Verification in a Web Shop
370
+
371
+ ```typescript
372
+ import { EudiploClient } from '@eudiplo/sdk-core';
373
+
374
+ const client = new EudiploClient({
375
+ baseUrl: process.env.EUDIPLO_URL,
376
+ clientId: process.env.EUDIPLO_CLIENT_ID,
377
+ clientSecret: process.env.EUDIPLO_CLIENT_SECRET,
378
+ });
379
+
380
+ // Express.js route handler
381
+ app.post('/api/verify-age', async (req, res) => {
382
+ const { uri, sessionId } = await client.createPresentationRequest({
383
+ configId: 'age-over-18',
384
+ redirectUri: `${req.headers.origin}/checkout`,
385
+ });
386
+
387
+ res.json({ qrCodeUri: uri, sessionId });
388
+ });
389
+
390
+ app.get('/api/verify-age/:sessionId', async (req, res) => {
391
+ const session = await client.getSession(req.params.sessionId);
392
+ res.json({
393
+ status: session.status,
394
+ verified: session.status === 'completed',
395
+ });
396
+ });
397
+ ```
398
+
399
+ ### React Hook Example
400
+
401
+ ```typescript
402
+ import { useState, useEffect } from 'react';
403
+ import { EudiploClient } from '@eudiplo/sdk-core';
404
+
405
+ const client = new EudiploClient({...});
406
+
407
+ function useAgeVerification(configId: string) {
408
+ const [uri, setUri] = useState<string>();
409
+ const [status, setStatus] = useState<string>('idle');
410
+ const [verified, setVerified] = useState(false);
411
+
412
+ const startVerification = async () => {
413
+ setStatus('pending');
414
+ const { uri, sessionId } = await client.createPresentationRequest({ configId });
415
+ setUri(uri);
416
+
417
+ try {
418
+ const session = await client.waitForSession(sessionId, {
419
+ onUpdate: (s) => setStatus(s.status)
420
+ });
421
+ setVerified(true);
422
+ setStatus('completed');
423
+ } catch (e) {
424
+ setStatus('failed');
425
+ }
426
+ };
427
+
428
+ return { uri, status, verified, startVerification };
429
+ }
430
+ ```
431
+
432
+ ## Advanced: Direct API Access
433
+
434
+ For advanced use cases, you can access the generated API functions directly:
435
+
436
+ ```typescript
437
+ import {
438
+ client,
439
+ sessionControllerGetAllSessions,
440
+ credentialConfigControllerGetConfigs,
441
+ } from '@eudiplo/sdk-core/api';
442
+
443
+ // Configure the client
444
+ client.setConfig({
445
+ baseUrl: 'https://eudiplo.example.com',
446
+ headers: { Authorization: 'Bearer your-token' },
447
+ });
448
+
449
+ // Use any API endpoint
450
+ const configs = await credentialConfigControllerGetConfigs({});
451
+ ```
452
+
453
+ ## Requirements
454
+
455
+ - Node.js 20+ (uses native `fetch`)
456
+ - For older environments, use a `fetch` polyfill
457
+
458
+ ## License
459
+
460
+ Apache-2.0
@@ -0,0 +1,5 @@
1
+ import { b as Config, C as Client } from '../../types.gen-DDunhhsd.mjs';
2
+
3
+ declare const createClient: (config?: Config) => Client;
4
+
5
+ export { createClient };
@@ -0,0 +1,5 @@
1
+ import { b as Config, C as Client } from '../../types.gen-DDunhhsd.js';
2
+
3
+ declare const createClient: (config?: Config) => Client;
4
+
5
+ export { createClient };