dataspace-client-sdk-node 0.1.1 → 0.2.0

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 (37) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +44 -1
  3. package/dist/client.d.ts +153 -33
  4. package/dist/client.js +619 -93
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/types.d.ts +112 -1
  8. package/dist/vp-token.d.ts +37 -0
  9. package/dist/vp-token.js +56 -0
  10. package/docs/API.md +19 -4
  11. package/docs/BACKEND_NODE_INTEGRATION.md +249 -0
  12. package/docs/CONTROLLER_FLOW_STEP_BY_STEP.md +283 -0
  13. package/docs/DATA_MODEL_ALIGNMENT.md +37 -13
  14. package/docs/DEVELOPER_USE_CASES.md +10 -2
  15. package/docs/E2E_LOCAL_GW_UC5.md +49 -0
  16. package/docs/ENDPOINT_ID_CATALOG.md +90 -0
  17. package/docs/LEGAL_ORGANIZATION_FLOW_STEP_BY_STEP.md +84 -0
  18. package/docs/PERSONAL_FLOW_STEP_BY_STEP.md +70 -0
  19. package/docs/PORTAL_BACKEND_INTEGRATION_HANDOVER.md +343 -0
  20. package/docs/PRACTITIONER_FLOW_STEP_BY_STEP.md +182 -0
  21. package/docs/REACT_WEB_INTEGRATION.md +72 -0
  22. package/examples/e2e-bootstrap-tenant.mjs +3 -2
  23. package/examples/e2e-individual-flow.mjs +13 -8
  24. package/examples/host-activate-and-employee.mjs +3 -2
  25. package/examples/smoke-legal-org-local.mjs +40 -0
  26. package/package.json +4 -3
  27. package/src/client.ts +784 -132
  28. package/src/index.ts +1 -0
  29. package/src/types.ts +123 -1
  30. package/src/vp-token.ts +91 -0
  31. package/tests/client.test.mjs +491 -0
  32. package/tests/fixtures/ica-vp-minimal.json +67 -0
  33. package/tests/helpers/vp-token-fixture.mjs +23 -0
  34. package/tests/live-gw-uc5.e2e.test.mjs +108 -0
  35. package/SDK_PARITY_MAP.md +0 -120
  36. package/TODO_PROMPT_NEXT_STEPS.md +0 -185
  37. package/artifacts/update-smart-wallet.js +0 -1016
package/src/index.ts CHANGED
@@ -4,5 +4,6 @@
4
4
  // See subjectVaultPhoneResolution.test.ts for context and migration plan.
5
5
  export * from './types.js';
6
6
  export * from './builders.js';
7
+ export * from './vp-token.js';
7
8
  export * from './client.js';
8
9
  export * from './sdk/dataspace-wallet-sdk-node/index.js';
package/src/types.ts CHANGED
@@ -195,6 +195,26 @@ export type FamilyOrganizationSummary = {
195
195
  updatedAt?: string;
196
196
  };
197
197
 
198
+ export type OfferPreview = {
199
+ offerId?: string;
200
+ amount?: string;
201
+ currency?: string;
202
+ seats?: number;
203
+ planName?: string;
204
+ sku?: string;
205
+ paymentMethod?: string;
206
+ checkoutUrl?: string;
207
+ };
208
+
209
+ export type OfferInfo = OfferPreview;
210
+
211
+ export type EndpointSelector = {
212
+ section: string;
213
+ format: string;
214
+ resourceType: string;
215
+ action: string;
216
+ };
217
+
198
218
  /**
199
219
  * Input for organization activation in GW using ICA-derived proof material.
200
220
  *
@@ -203,9 +223,40 @@ export type FamilyOrganizationSummary = {
203
223
  */
204
224
  export type GatewayOrganizationActivationInput = {
205
225
  vpToken: string;
226
+ /** Generic requested seats/members for initial offer sizing. Defaults to 2. */
227
+ numberOfMembers?: number;
206
228
  organizationVc?: string;
207
229
  legalRepresentativeVc?: string;
208
230
  regulatoryEvidence?: Record<string, unknown>;
231
+ /** @deprecated Prefer `numberOfMembers` and explicit input fields. */
232
+ additionalClaims?: Record<string, unknown>;
233
+ };
234
+
235
+ export type GatewayOrganizationActivationSimpleInput = {
236
+ jurisdiction?: string;
237
+ sector?: string;
238
+ vpToken: string;
239
+ serviceProviderDidWeb?: string;
240
+ serviceProviderUrl?: string;
241
+ controllerEmail?: string;
242
+ controllerTelephone?: string;
243
+ controllerRole: string;
244
+ numberOfMembers?: number;
245
+ timeoutSeconds?: number;
246
+ intervalSeconds?: number;
247
+ organizationVc?: string;
248
+ legalRepresentativeVc?: string;
249
+ regulatoryEvidence?: Record<string, unknown>;
250
+ additionalClaims?: Record<string, unknown>;
251
+ };
252
+
253
+ export type LegalOrganizationOrderSimpleInput = {
254
+ jurisdiction?: string;
255
+ sector?: string;
256
+ offerId: string;
257
+ timeoutSeconds?: number;
258
+ intervalSeconds?: number;
259
+ dataType?: string;
209
260
  additionalClaims?: Record<string, unknown>;
210
261
  };
211
262
 
@@ -219,6 +270,17 @@ export type EmployeeDeviceActivationInput = {
219
270
  pollOptions?: PollOptions;
220
271
  };
221
272
 
273
+ export type EmployeeDeviceActivationSimpleInput = {
274
+ tenantId?: string;
275
+ jurisdiction?: string;
276
+ sector?: string;
277
+ activationCode: string;
278
+ idToken: string;
279
+ dcrPayload: Record<string, unknown>;
280
+ timeoutSeconds?: number;
281
+ intervalSeconds?: number;
282
+ };
283
+
222
284
  /**
223
285
  * Result of device activation flow.
224
286
  *
@@ -256,6 +318,40 @@ export type SubjectOrganizationBootstrapResult = {
256
318
  confirmation?: SubmitAndPollResult;
257
319
  };
258
320
 
321
+ export type IndividualOrganizationBootstrapSimpleInput = {
322
+ tenantId?: string;
323
+ jurisdiction?: string;
324
+ sector?: string;
325
+ alternateName: string;
326
+ controllerEmail?: string;
327
+ controllerTelephone?: string;
328
+ controllerRole?: string; // default org.hl7.v3.RoleCode|RESPRSN
329
+ timeoutSeconds?: number;
330
+ intervalSeconds?: number;
331
+ additionalClaims?: Record<string, unknown>;
332
+ };
333
+
334
+ export type IndividualOrganizationBootstrapSimpleResult = {
335
+ registration: SubmitAndPollResult;
336
+ offerId: string;
337
+ confirmation: SubmitAndPollResult;
338
+ };
339
+
340
+ export type IndividualOrganizationStartSimpleResult = {
341
+ registration: SubmitAndPollResult;
342
+ offerId: string;
343
+ offerPreview: OfferPreview;
344
+ };
345
+
346
+ export type IndividualOrganizationConfirmOrderSimpleInput = {
347
+ tenantId?: string;
348
+ jurisdiction?: string;
349
+ sector?: string;
350
+ offerId: string;
351
+ timeoutSeconds?: number;
352
+ intervalSeconds?: number;
353
+ };
354
+
259
355
  /**
260
356
  * Input for UC 5.5 IPS/FHIR import and index update.
261
357
  */
@@ -413,6 +509,8 @@ export type ClientOptions = {
413
509
  bearerToken?: string;
414
510
  defaultHeaders?: Record<string, string>;
415
511
  wallet?: WalletProvider;
512
+ /** Optional default tenant context so calls can omit ctx repeatedly. */
513
+ ctx?: RouteContext;
416
514
  };
417
515
 
418
516
  /**
@@ -437,6 +535,8 @@ export type BackendPkceAuthOptions = {
437
535
  /** Requested scopes for the SMART bearer token. */
438
536
  scopes: string[];
439
537
  /** Cache key for the resulting bearer token. Defaults to `pkce:<apiKey prefix>`. */
538
+ tokenCacheKey?: string;
539
+ /** @deprecated Use `tokenCacheKey`. */
440
540
  endpointId?: string;
441
541
  /** PKCE code verifier. Auto-generated with randomUUID if not provided. */
442
542
  codeVerifier?: string;
@@ -447,6 +547,8 @@ export type BackendPkceAuthOptions = {
447
547
  export type BackendPkceAuthResult = {
448
548
  /** `fetched`: new token obtained. `cached`: valid token already in cache. `failed`: flow error. */
449
549
  status: 'fetched' | 'cached' | 'failed';
550
+ tokenCacheKey: string;
551
+ /** @deprecated Use `tokenCacheKey`. */
450
552
  endpointId: string;
451
553
  accessToken: string;
452
554
  tokenType: string;
@@ -458,6 +560,8 @@ export type BackendPkceAuthResult = {
458
560
  export type BackendSmartAuthOptions = {
459
561
  clientId: string;
460
562
  scopes: string[];
563
+ tokenCacheKey?: string;
564
+ /** @deprecated Use `tokenCacheKey`. */
461
565
  endpointId?: string;
462
566
  tokenUrl?: string;
463
567
  tokenPath?: string;
@@ -471,6 +575,8 @@ export type BackendSmartAuthOptions = {
471
575
  export type BackendSmartAuthResult = {
472
576
  status: 'fetched' | 'cached' | 'failed';
473
577
  profile: 'smart-backend.v1';
578
+ tokenCacheKey: string;
579
+ /** @deprecated Use `tokenCacheKey`. */
474
580
  endpointId: string;
475
581
  accessToken?: string;
476
582
  tokenType?: string;
@@ -481,12 +587,28 @@ export type BackendSmartAuthResult = {
481
587
  };
482
588
 
483
589
  export type SmartTokenExchangeInput = {
484
- endpointId: string;
590
+ tokenCacheKey: string;
591
+ /** @deprecated Use `tokenCacheKey`. */
592
+ endpointId?: string;
485
593
  scopes: string[];
486
594
  exchangePayload: Record<string, unknown>;
487
595
  path?: string;
488
596
  };
489
597
 
598
+ export type SmartTokenRequestSimpleInput = {
599
+ tenantId?: string;
600
+ jurisdiction?: string;
601
+ sector?: string;
602
+ idToken: string;
603
+ scopes: string[];
604
+ tokenCacheKey?: string;
605
+ /** @deprecated Use `tokenCacheKey`. */
606
+ endpointId?: string;
607
+ timeoutSeconds?: number;
608
+ intervalSeconds?: number;
609
+ additionalClaims?: Record<string, unknown>;
610
+ };
611
+
490
612
  export type SmartTokenExchangeResult = {
491
613
  status: 'fetched' | 'cached' | 'failed';
492
614
  accessToken?: string;
@@ -0,0 +1,91 @@
1
+ export type VpTokenHeader = {
2
+ alg: string;
3
+ typ?: string;
4
+ kid?: string;
5
+ [key: string]: unknown;
6
+ };
7
+
8
+ export type VpTokenPayload = {
9
+ iss: string;
10
+ sub?: string;
11
+ aud?: string;
12
+ jti?: string;
13
+ iat?: number;
14
+ exp?: number;
15
+ nonce?: string;
16
+ vp: {
17
+ '@context'?: unknown;
18
+ type?: unknown;
19
+ holder?: string;
20
+ verifiableCredential: string[];
21
+ [key: string]: unknown;
22
+ };
23
+ [key: string]: unknown;
24
+ };
25
+
26
+ function toB64UrlJson(input: unknown): string {
27
+ return Buffer.from(JSON.stringify(input), 'utf-8').toString('base64url');
28
+ }
29
+
30
+ function fallbackId(): string {
31
+ const rand = Math.random().toString(36).slice(2, 10);
32
+ return `id-${Date.now()}-${rand}`;
33
+ }
34
+
35
+ export function generateUuidLike(): string {
36
+ const fn = (globalThis as any)?.crypto?.randomUUID;
37
+ if (typeof fn === 'function') return fn.call((globalThis as any).crypto);
38
+ return fallbackId();
39
+ }
40
+
41
+ export function buildEpochWindow(ttlSeconds = 300): { iat: number; exp: number } {
42
+ const iat = Math.floor(Date.now() / 1000);
43
+ return { iat, exp: iat + Math.max(1, Math.floor(ttlSeconds)) };
44
+ }
45
+
46
+ export function createVP(input?: Partial<VpTokenPayload>): VpTokenPayload {
47
+ const ttl = input?.exp && input?.iat ? undefined : buildEpochWindow(300);
48
+ const jti = input?.jti || generateUuidLike();
49
+ const nonce = input?.nonce || generateUuidLike();
50
+ return {
51
+ iss: String(input?.iss || ''),
52
+ sub: input?.sub,
53
+ aud: input?.aud,
54
+ jti,
55
+ iat: input?.iat ?? ttl?.iat,
56
+ exp: input?.exp ?? ttl?.exp,
57
+ nonce,
58
+ vp: {
59
+ '@context': ['https://www.w3.org/2018/credentials/v1'],
60
+ type: ['VerifiablePresentation'],
61
+ holder: input?.vp?.holder || input?.iss || '',
62
+ verifiableCredential: [],
63
+ ...(input?.vp || {}),
64
+ },
65
+ };
66
+ }
67
+
68
+ export function addVC(vpPayload: VpTokenPayload, vcJwt: string): VpTokenPayload {
69
+ const v = String(vcJwt || '').trim();
70
+ if (v) vpPayload.vp.verifiableCredential.push(v);
71
+ return vpPayload;
72
+ }
73
+
74
+ export function prepareForSignature(header: VpTokenHeader, payload: VpTokenPayload): {
75
+ encodedHeader: string;
76
+ encodedPayload: string;
77
+ signingInput: string;
78
+ } {
79
+ const encodedHeader = toB64UrlJson(header);
80
+ const encodedPayload = toB64UrlJson(payload);
81
+ return { encodedHeader, encodedPayload, signingInput: `${encodedHeader}.${encodedPayload}` };
82
+ }
83
+
84
+ export function prepareBytesForSignature(header: VpTokenHeader, payload: VpTokenPayload): Uint8Array {
85
+ const { signingInput } = prepareForSignature(header, payload);
86
+ return new TextEncoder().encode(signingInput);
87
+ }
88
+
89
+ export function buildVpTokenCompact(encodedHeader: string, encodedPayload: string, signatureBase64Url: string): string {
90
+ return `${encodedHeader}.${encodedPayload}.${String(signatureBase64Url || '').trim()}`;
91
+ }