dataspace-client-sdk-node 0.1.1
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 +310 -0
- package/SDK_PARITY_MAP.md +120 -0
- package/TODO_PROMPT_NEXT_STEPS.md +185 -0
- package/artifacts/update-smart-wallet.js +1016 -0
- package/dist/builders.d.ts +12 -0
- package/dist/builders.js +17 -0
- package/dist/client.d.ts +333 -0
- package/dist/client.js +1229 -0
- package/dist/consent/pdfSignatureVerification.d.ts +18 -0
- package/dist/consent/pdfSignatureVerification.js +23 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -0
- package/dist/sdk/dataspace-wallet-sdk-node/MultiWalletClient.d.ts +9 -0
- package/dist/sdk/dataspace-wallet-sdk-node/MultiWalletClient.js +21 -0
- package/dist/sdk/dataspace-wallet-sdk-node/WalletClient.d.ts +26 -0
- package/dist/sdk/dataspace-wallet-sdk-node/WalletClient.js +36 -0
- package/dist/sdk/dataspace-wallet-sdk-node/index.d.ts +6 -0
- package/dist/sdk/dataspace-wallet-sdk-node/index.js +6 -0
- package/dist/sdk/dataspace-wallet-sdk-node/provider.d.ts +24 -0
- package/dist/sdk/dataspace-wallet-sdk-node/provider.js +1 -0
- package/dist/sdk/dataspace-wallet-sdk-node/providers/memory-provider.d.ts +41 -0
- package/dist/sdk/dataspace-wallet-sdk-node/providers/memory-provider.js +216 -0
- package/dist/sdk/dataspace-wallet-sdk-node/providers/seed-provider.d.ts +22 -0
- package/dist/sdk/dataspace-wallet-sdk-node/providers/seed-provider.js +28 -0
- package/dist/sdk/dataspace-wallet-sdk-node/types.d.ts +51 -0
- package/dist/sdk/dataspace-wallet-sdk-node/types.js +1 -0
- package/dist/types.d.ts +445 -0
- package/dist/types.js +1 -0
- package/docs/API.md +745 -0
- package/docs/DATA_MODEL_ALIGNMENT.md +31 -0
- package/docs/DATA_PLANES_SCOPE_MATRIX.md +51 -0
- package/docs/DEVELOPER_USE_CASES.md +253 -0
- package/docs/E2E_BOOTSTRAP.md +54 -0
- package/docs/TODO_SMART_EHR_COMPAT.md +58 -0
- package/examples/backend-pkce-auth.mjs +119 -0
- package/examples/conversion-upload.mjs +52 -0
- package/examples/e2e-bootstrap-tenant.mjs +126 -0
- package/examples/e2e-individual-flow.mjs +43 -0
- package/examples/host-activate-and-employee.mjs +75 -0
- package/package.json +26 -0
- package/src/builders.ts +28 -0
- package/src/client.ts +1626 -0
- package/src/consent/pdfSignatureVerification.ts +41 -0
- package/src/index.ts +8 -0
- package/src/sdk/dataspace-wallet-sdk-node/MultiWalletClient.ts +25 -0
- package/src/sdk/dataspace-wallet-sdk-node/WalletClient.ts +63 -0
- package/src/sdk/dataspace-wallet-sdk-node/index.ts +6 -0
- package/src/sdk/dataspace-wallet-sdk-node/provider.ts +44 -0
- package/src/sdk/dataspace-wallet-sdk-node/providers/memory-provider.ts +310 -0
- package/src/sdk/dataspace-wallet-sdk-node/providers/seed-provider.ts +31 -0
- package/src/sdk/dataspace-wallet-sdk-node/types.ts +61 -0
- package/src/types.ts +497 -0
- package/tests/client.test.mjs +892 -0
- package/tests/uc5-org-onboarding.flow.test.mjs +145 -0
- package/tests/uc5-subject-data.flow.test.mjs +198 -0
- package/tsconfig.json +13 -0
package/docs/API.md
ADDED
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
# dataspace-client-sdk-node — API Reference
|
|
2
|
+
|
|
3
|
+
All methods belong to the `DataspaceNodeClient` class unless stated otherwise.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- [Setup](#setup)
|
|
8
|
+
- [Types](#types)
|
|
9
|
+
- [Constructor](#constructor)
|
|
10
|
+
- [Path helpers](#path-helpers)
|
|
11
|
+
- [Generic builders](#generic-builders)
|
|
12
|
+
- [Host registry (controller-level)](#host-registry-controller-level)
|
|
13
|
+
- [Individual — Family Organization](#individual--family-organization)
|
|
14
|
+
- [Individual — FHIR resources](#individual--fhir-resources)
|
|
15
|
+
- [Entity — Employee](#entity--employee)
|
|
16
|
+
- [Identity / Auth](#identity--auth)
|
|
17
|
+
- [DataConversion upload](#dataconversion-upload)
|
|
18
|
+
- [Task debug](#task-debug)
|
|
19
|
+
- [Auth methods](#auth-methods)
|
|
20
|
+
- [authenticateBackendPkceAndExchange](#authenticatebackendpkceandexchange)
|
|
21
|
+
- [authenticateBackendSmartStandard](#authenticatebackendsmartstandard)
|
|
22
|
+
- [getCachedBearerToken](#getcachedbearertoken)
|
|
23
|
+
- [Transport methods](#transport-methods)
|
|
24
|
+
- [submitBatch](#submitbatch)
|
|
25
|
+
- [submitBatchEncrypted](#submitbatchencrypted)
|
|
26
|
+
- [postJson](#postjson)
|
|
27
|
+
- [postFormData](#postformdata)
|
|
28
|
+
- [uploadConversionFile](#uploadconversionfile)
|
|
29
|
+
- [pollBatchResponse](#pollbatchresponse)
|
|
30
|
+
- [submitAndPoll](#submitandpoll)
|
|
31
|
+
- [pollUntilComplete](#polluntilcomplete)
|
|
32
|
+
- [High-level helpers](#high-level-helpers)
|
|
33
|
+
- [createPhoneReminderTasks](#createphoneremiindertasks)
|
|
34
|
+
- [searchFamilyOrganization](#searchfamilyorganization)
|
|
35
|
+
- [Standalone exports](#standalone-exports)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Setup
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install
|
|
43
|
+
npm run build
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { DataspaceNodeClient, createDidcommPlainMessage } from 'dataspace-client-sdk-node';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Types
|
|
53
|
+
|
|
54
|
+
### `RouteContext`
|
|
55
|
+
|
|
56
|
+
Tenant-scoped routing context required by most path helpers and high-level methods.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
type RouteContext = {
|
|
60
|
+
tenantId: string; // e.g. 'acme'
|
|
61
|
+
jurisdiction: string; // ISO-3166 alpha-2, e.g. 'ES'
|
|
62
|
+
sector: string; // e.g. 'health-care', 'animal-care'
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `HostRouteContext`
|
|
67
|
+
|
|
68
|
+
Used for host/controller-level registry paths (no `tenantId`).
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
type HostRouteContext = {
|
|
72
|
+
jurisdiction: string;
|
|
73
|
+
sector: string;
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `SubmitResponse`
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
type SubmitResponse = {
|
|
81
|
+
status: number;
|
|
82
|
+
location?: string; // async poll URL from Location header
|
|
83
|
+
body: unknown;
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### `PollResult`
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
type PollResult = {
|
|
91
|
+
status: number;
|
|
92
|
+
body: unknown;
|
|
93
|
+
attempts: number;
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `SubmitAndPollResult`
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
type SubmitAndPollResult = {
|
|
101
|
+
submit: SubmitResponse;
|
|
102
|
+
poll: PollResult;
|
|
103
|
+
};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `PollOptions`
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
type PollOptions = {
|
|
110
|
+
timeoutMs?: number; // default 20000
|
|
111
|
+
intervalMs?: number; // default 1000
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `FamilyRegistrationStatus`
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
type FamilyRegistrationStatus = 'new_created' | 'resume_required' | 'already_exists' | 'not_found';
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `FamilyOrganizationSummary`
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
type FamilyOrganizationSummary = {
|
|
125
|
+
organizationId: string;
|
|
126
|
+
status: FamilyRegistrationStatus;
|
|
127
|
+
controllerPhone?: string;
|
|
128
|
+
nickname?: string;
|
|
129
|
+
notificationPhone?: string;
|
|
130
|
+
sector?: string;
|
|
131
|
+
jurisdiction?: string;
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `CreatePhoneReminderTasksInput`
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
type CreatePhoneReminderTasksInput = {
|
|
139
|
+
windows: Array<{ offsetMinutes: number; remindAt: string }>; // remindAt = ISO-8601
|
|
140
|
+
locale?: string;
|
|
141
|
+
callSid?: string;
|
|
142
|
+
notificationPhone?: string;
|
|
143
|
+
controllerPhone?: string;
|
|
144
|
+
subjectRef: string; // e.g. 'Person/+34600000001'
|
|
145
|
+
ownerRef: string; // e.g. 'RelatedPerson/+34699999999'
|
|
146
|
+
focusRef: string; // e.g. 'Appointment/2026-05-10T10:00:00.000Z'
|
|
147
|
+
reminderSummary?: string;
|
|
148
|
+
description?: string;
|
|
149
|
+
maxAttempts?: number;
|
|
150
|
+
dataType?: string;
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Constructor
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
new DataspaceNodeClient(options: ClientOptions)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
| Option | Type | Required | Description |
|
|
163
|
+
|---|---|---|---|
|
|
164
|
+
| `baseUrl` | `string` | ✅ | Base URL of the GW/UNID API, e.g. `http://localhost:3000` |
|
|
165
|
+
| `bearerToken` | `string` | | Static bearer token for `Authorization` header |
|
|
166
|
+
| `defaultHeaders` | `Record<string, string>` | | Extra headers added to every request |
|
|
167
|
+
| `wallet` | `WalletProvider` | | Required only for `submitBatchEncrypted` and `authenticateBackendPkceAndExchange` with JWK provisioning |
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const client = new DataspaceNodeClient({
|
|
171
|
+
baseUrl: 'http://localhost:3000',
|
|
172
|
+
bearerToken: 'my-api-key',
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Path helpers
|
|
179
|
+
|
|
180
|
+
Path helpers return URL strings. They do **not** make network requests.
|
|
181
|
+
Every path has a submit path (`_batch` / `_search`) and a matching poll path (`_batch-response` / `_search-response`).
|
|
182
|
+
|
|
183
|
+
### Generic builders
|
|
184
|
+
|
|
185
|
+
#### `v1Path(ctx, section, format, resourceType, action): string`
|
|
186
|
+
|
|
187
|
+
Builds any GW v1 route. Use when no dedicated helper exists.
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
/{tenantId}/cds-{jurisdiction}/v1/{sector}/{section}/{format}/{resourceType}/{action}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
client.v1Path(ctx, 'individual', 'org.schema', 'Organization', '_batch')
|
|
195
|
+
// → /acme/cds-ES/v1/health-care/individual/org.schema/Organization/_batch
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### `tenantIdentityPath(ctx, prefix, action): string`
|
|
199
|
+
|
|
200
|
+
Builds identity/auth routes scoped to a service prefix (`host`, `publisher`, `ica`).
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
/{prefix}/cds-{jurisdiction}/v1/{sector}/{tenantId}/identity/auth/{action}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### `hostRegistryPath(ctx, resourceType, action): string`
|
|
207
|
+
|
|
208
|
+
Builds host-level registry routes (no `tenantId`).
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
/host/cds-{jurisdiction}/v1/{sector}/registry/org.schema/{resourceType}/{action}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### Host registry (controller-level)
|
|
217
|
+
|
|
218
|
+
| Method | Returns | Route |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| `hostRegistryOrganizationBatchPath(ctx)` | submit path | `/host/.../registry/org.schema/Organization/_batch` |
|
|
221
|
+
| `hostRegistryOrganizationPollPath(ctx)` | poll path | `.../_batch-response` |
|
|
222
|
+
| `hostRegistryOrganizationActivatePath(ctx)` | submit path | `.../_activate` |
|
|
223
|
+
| `hostRegistryOrganizationActivatePollPath(ctx)` | poll path | `.../_activate-response` |
|
|
224
|
+
| `hostRegistryOrderBatchPath(ctx)` | submit path | `.../Order/_batch` |
|
|
225
|
+
| `hostRegistryOrderPollPath(ctx)` | poll path | `.../Order/_batch-response` |
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const ctx: HostRouteContext = { jurisdiction: 'ES', sector: 'health-care' };
|
|
229
|
+
|
|
230
|
+
const result = await client.submitAndPoll(
|
|
231
|
+
client.hostRegistryOrganizationBatchPath(ctx),
|
|
232
|
+
client.hostRegistryOrganizationPollPath(ctx),
|
|
233
|
+
payload,
|
|
234
|
+
);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
### Individual — Family Organization
|
|
240
|
+
|
|
241
|
+
| Method | Returns | Route |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| `individualFamilyOrganizationBatchPath(ctx)` | submit | `.../individual/org.schema/Organization/_batch` |
|
|
244
|
+
| `individualFamilyOrganizationPollPath(ctx)` | poll | `.../_batch-response` |
|
|
245
|
+
| `individualFamilyOrganizationSearchPath(ctx)` | submit | `.../Organization/_search` |
|
|
246
|
+
| `individualFamilyOrganizationSearchPollPath(ctx)` | poll | `.../Organization/_search-response` |
|
|
247
|
+
| `individualFamilyOrderBatchPath(ctx)` | submit | `.../org.schema/Order/_batch` |
|
|
248
|
+
| `individualFamilyOrderPollPath(ctx)` | poll | `.../Order/_batch-response` |
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
const ctx: RouteContext = { tenantId: 'acme', jurisdiction: 'ES', sector: 'health-care' };
|
|
252
|
+
|
|
253
|
+
// Register or resume a family organization
|
|
254
|
+
const payload = createDidcommPlainMessage({
|
|
255
|
+
iss: '+34600000001',
|
|
256
|
+
aud: 'did:web:api.acme.org',
|
|
257
|
+
body: {
|
|
258
|
+
data: [{
|
|
259
|
+
type: 'Family-registration-form-v1.0',
|
|
260
|
+
meta: {
|
|
261
|
+
claims: {
|
|
262
|
+
'@context': 'org.schema',
|
|
263
|
+
'org.schema.Organization.telephone': '+34611111111', // notification phone (subject)
|
|
264
|
+
'org.schema.Organization.creator': '+34600000001', // controller phone
|
|
265
|
+
'org.schema.Organization.owner.telephone': '+34600000001', // controller (indexed)
|
|
266
|
+
'org.schema.Organization.alternateName': 'Maria', // usualname (indexed)
|
|
267
|
+
'org.schema.Service.category': 'health-care',
|
|
268
|
+
'org.schema.Organization.addressCountry': 'ES',
|
|
269
|
+
'org.schema.Organization.identifierValue': 'f0d4b66d-7e28-4fa2-91b7-7041e57f4f90',
|
|
270
|
+
'@type': 'receipt',
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
}],
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const result = await client.submitAndPoll(
|
|
278
|
+
client.individualFamilyOrganizationBatchPath(ctx),
|
|
279
|
+
client.individualFamilyOrganizationPollPath(ctx),
|
|
280
|
+
payload,
|
|
281
|
+
);
|
|
282
|
+
// result.poll.body contains 'org.schema.FamilyRegistration.status': 'new_created' | 'already_exists' | 'resume_required'
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
> Prefer the high-level [`searchFamilyOrganization`](#searchfamilyorganization) instead of calling the search path manually.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
### Individual — FHIR resources
|
|
290
|
+
|
|
291
|
+
| Method | Returns | Route |
|
|
292
|
+
|---|---|---|
|
|
293
|
+
| `individualRelatedPersonBatchPath(ctx)` | submit | `.../individual/org.hl7.fhir.api/RelatedPerson/_batch` |
|
|
294
|
+
| `individualRelatedPersonPollPath(ctx)` | poll | `.../_batch-response` |
|
|
295
|
+
| `individualObservationBatchPath(ctx)` | submit | `.../org.hl7.fhir.api/Observation/_batch` |
|
|
296
|
+
| `individualObservationPollPath(ctx)` | poll | `.../_batch-response` |
|
|
297
|
+
| `individualCommunicationBatchPath(ctx)` | submit | `.../org.hl7.fhir.r4/Communication/_batch` |
|
|
298
|
+
| `individualCommunicationPollPath(ctx)` | poll | `.../_batch-response` |
|
|
299
|
+
| `individualTaskBatchPath(ctx)` | submit | `.../org.hl7.fhir.api/Task/_batch` |
|
|
300
|
+
| `individualTaskPollPath(ctx)` | poll | `.../_batch-response` |
|
|
301
|
+
| `individualConsentR4BatchPath(ctx)` | submit | `.../org.hl7.fhir.r4/Consent/_batch` |
|
|
302
|
+
| `individualConsentR4PollPath(ctx)` | poll | `.../_batch-response` |
|
|
303
|
+
| `individualCompositionR4BatchPath(ctx)` | submit | `.../org.hl7.fhir.r4/Composition/_batch` |
|
|
304
|
+
| `individualCompositionR4PollPath(ctx)` | poll | `.../_batch-response` |
|
|
305
|
+
| `individualLegacyPersonBatchPath(ctx)` | submit | `.../org.schema/Person/_batch` (legacy) |
|
|
306
|
+
| `digitalTwinCompositionApiBatchPath(ctx)` | submit | `.../digitaltwin/org.hl7.fhir.api/Composition/_batch` |
|
|
307
|
+
| `digitalTwinCompositionApiPollPath(ctx)` | poll | `.../_batch-response` |
|
|
308
|
+
| `digitalTwinCompositionR4BatchPath(ctx)` | submit | `.../digitaltwin/org.hl7.fhir.r4/Composition/_batch` |
|
|
309
|
+
| `digitalTwinCompositionR4PollPath(ctx)` | poll | `.../_batch-response` |
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
// Submit a FHIR Task
|
|
313
|
+
const taskPayload = createDidcommPlainMessage({
|
|
314
|
+
iss: ctx.tenantId,
|
|
315
|
+
aud: ctx.tenantId,
|
|
316
|
+
body: {
|
|
317
|
+
data: [{
|
|
318
|
+
type: 'Task',
|
|
319
|
+
request: { method: 'POST' },
|
|
320
|
+
resource: {
|
|
321
|
+
resourceType: 'Task',
|
|
322
|
+
id: 'task-abc',
|
|
323
|
+
description: 'Medication reminder',
|
|
324
|
+
meta: {
|
|
325
|
+
claims: {
|
|
326
|
+
status: 'scheduled',
|
|
327
|
+
subject: 'Person/+34600000001',
|
|
328
|
+
channel: 'phone',
|
|
329
|
+
'trigger-type': 'phone-call',
|
|
330
|
+
'execution-period-start': '2026-05-10T09:00:00.000Z',
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
}],
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const result = await client.submitAndPoll(
|
|
339
|
+
client.individualTaskBatchPath(ctx),
|
|
340
|
+
client.individualTaskPollPath(ctx),
|
|
341
|
+
taskPayload,
|
|
342
|
+
);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
### Entity — Employee
|
|
348
|
+
|
|
349
|
+
| Method | Returns | Route |
|
|
350
|
+
|---|---|---|
|
|
351
|
+
| `employeeBatchPath(ctx)` | submit | `.../entity/org.schema/Employee/_batch` |
|
|
352
|
+
| `employeePollPath(ctx)` | poll | `.../_batch-response` |
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
const result = await client.submitAndPoll(
|
|
356
|
+
client.employeeBatchPath(ctx),
|
|
357
|
+
client.employeePollPath(ctx),
|
|
358
|
+
employeePayload,
|
|
359
|
+
);
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
### Identity / Auth
|
|
365
|
+
|
|
366
|
+
These are used internally by [`authenticateBackendPkceAndExchange`](#authenticatebackendpkceandexchange). Exposed for custom flows.
|
|
367
|
+
|
|
368
|
+
| Method | Route |
|
|
369
|
+
|---|---|
|
|
370
|
+
| `identityDeviceDcrPath(ctx)` | `host/.../identity/auth/_dcr` |
|
|
371
|
+
| `identityDeviceDcrPollPath(ctx)` | `.../_dcr-response` |
|
|
372
|
+
| `identityCodePath(ctx)` | `.../_code` |
|
|
373
|
+
| `identityCodePollPath(ctx)` | `.../_code-response` |
|
|
374
|
+
| `identitySmartTokenPath(ctx)` | `.../_token` |
|
|
375
|
+
| `identitySmartTokenPollPath(ctx)` | `.../_token-response` |
|
|
376
|
+
| `identityTokenExchangePath(ctx)` | `.../_exchange` |
|
|
377
|
+
| `identityTokenExchangePollPath(ctx)` | `.../_exchange-response` |
|
|
378
|
+
| `identityLicenseIssuePath(ctx)` | `.../_issue` |
|
|
379
|
+
| `identityFirebaseCustomPath(ctx)` | `.../_custom` |
|
|
380
|
+
| `identityFirebaseCustomPollPath(ctx)` | `.../_custom-response` |
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### DataConversion upload
|
|
385
|
+
|
|
386
|
+
| Method | Route |
|
|
387
|
+
|---|---|
|
|
388
|
+
| `conversionUploadPath(ctx, softwareId, sourceFormat)` | `.../conversion/{softwareId}/{sourceFormat}/_upload` |
|
|
389
|
+
| `conversionUploadPollPath(ctx, softwareId, sourceFormat)` | `.../_upload-response` |
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
const path = client.conversionUploadPath(ctx, 'qvet', 'xlsx');
|
|
393
|
+
// → /acme/cds-ES/v1/health-care/conversion/qvet/xlsx/_upload
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### Task debug
|
|
399
|
+
|
|
400
|
+
| Method | Route |
|
|
401
|
+
|---|---|
|
|
402
|
+
| `taskDebugCallStartPath(ctx, format?)` | `.../individual/{format}/Task/_call-start` |
|
|
403
|
+
| `taskDebugLogsPath(ctx, format?)` | `.../individual/{format}/Task/_logs` |
|
|
404
|
+
|
|
405
|
+
`format` defaults to `'org.hl7.fhir.api'`.
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
// Trigger a debug voice call for a scheduled task
|
|
409
|
+
await client.postJson(client.taskDebugCallStartPath(ctx), { thid: 'task-abc123' });
|
|
410
|
+
|
|
411
|
+
// Poll logs
|
|
412
|
+
const logs = await client.postJson(client.taskDebugLogsPath(ctx), { thid: 'task-abc123' });
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## Auth methods
|
|
418
|
+
|
|
419
|
+
### `authenticateBackendPkceAndExchange`
|
|
420
|
+
|
|
421
|
+
Orchestrates the full identity-exchange.v1 backend auth flow:
|
|
422
|
+
**DCR → PKCE code → SMART token → bearer exchange**.
|
|
423
|
+
|
|
424
|
+
Tokens are cached in memory. Automatically refreshes on expiry.
|
|
425
|
+
|
|
426
|
+
```ts
|
|
427
|
+
const result = await client.authenticateBackendPkceAndExchange({
|
|
428
|
+
ctx: { tenantId: 'acme', jurisdiction: 'ES', sector: 'health-care' },
|
|
429
|
+
apiKey: 'my-api-key',
|
|
430
|
+
scopes: ['organization/Task.cruds', 'organization/Observation.rs'],
|
|
431
|
+
// Optional: provide your own wallet for JWK signing
|
|
432
|
+
// walletContext: { ... },
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
if (result.status === 'fetched' || result.status === 'cached') {
|
|
436
|
+
console.log(result.accessToken); // use as Bearer
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Returns** `BackendPkceAuthResult`:
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
type BackendPkceAuthResult =
|
|
444
|
+
| { status: 'fetched' | 'cached'; endpointId: string; accessToken: string; tokenType: string; scopes: string[] }
|
|
445
|
+
| { status: 'failed'; step: '_dcr' | '_code' | '_token' | '_exchange'; endpointId: string; accessToken: ''; tokenType: 'Bearer'; scopes: string[] };
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
### `authenticateBackendSmartStandard`
|
|
451
|
+
|
|
452
|
+
OAuth2 `client_credentials` flow using `private_key_jwt` assertion (SMART Backend Services profile).
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
const result = await client.authenticateBackendSmartStandard({
|
|
456
|
+
ctx: { tenantId: 'acme', jurisdiction: 'ES', sector: 'health-care' },
|
|
457
|
+
clientId: 'backend-service-client-id',
|
|
458
|
+
scopes: ['system/Task.rs'],
|
|
459
|
+
tokenUrl: 'https://auth.acme.org/token',
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
if (result.status === 'fetched' || result.status === 'cached') {
|
|
463
|
+
console.log(result.accessToken);
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
### `getCachedBearerToken`
|
|
470
|
+
|
|
471
|
+
Returns the cached bearer token for an `endpointId` if valid (>30s remaining), or `undefined`.
|
|
472
|
+
|
|
473
|
+
```ts
|
|
474
|
+
const token = client.getCachedBearerToken('pkce:my-api-key');
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Transport methods
|
|
480
|
+
|
|
481
|
+
### `submitBatch`
|
|
482
|
+
|
|
483
|
+
POST a DIDComm plaintext payload (`application/didcomm-plaintext+json`).
|
|
484
|
+
|
|
485
|
+
```ts
|
|
486
|
+
submitBatch(path: string, payload: unknown): Promise<SubmitResponse>
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
```ts
|
|
490
|
+
const { status, location } = await client.submitBatch(
|
|
491
|
+
client.individualTaskBatchPath(ctx),
|
|
492
|
+
payload,
|
|
493
|
+
);
|
|
494
|
+
// location header contains the poll URL
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
### `submitBatchEncrypted`
|
|
500
|
+
|
|
501
|
+
Sign and encrypt a DIDComm payload as JWS-in-JWE, then POST it with `Content-Type: application/didcomm-encrypted+json`.
|
|
502
|
+
|
|
503
|
+
Requires a configured `WalletProvider` in the client constructor.
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
submitBatchEncrypted(
|
|
507
|
+
path: string,
|
|
508
|
+
payload: Record<string, unknown>,
|
|
509
|
+
recipientEncryptionJwk: PublicJwk,
|
|
510
|
+
walletContext: WalletContext,
|
|
511
|
+
): Promise<SubmitResponse>
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
```ts
|
|
515
|
+
// recipientEncryptionJwk from GW /.well-known/jwks.json where use === 'enc'
|
|
516
|
+
const response = await client.submitBatchEncrypted(
|
|
517
|
+
client.individualFamilyOrganizationBatchPath(ctx),
|
|
518
|
+
payload,
|
|
519
|
+
recipientJwk,
|
|
520
|
+
walletCtx,
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
### `postJson`
|
|
527
|
+
|
|
528
|
+
POST a plain JSON body (`application/json`). Use for token endpoints and API key management.
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
postJson(path: string, payload: unknown): Promise<SubmitResponse>
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
```ts
|
|
535
|
+
const response = await client.postJson('/host/admin/api-keys', {
|
|
536
|
+
agent: { email: 'service@example.com' },
|
|
537
|
+
scope: ['organization/Task.cruds'],
|
|
538
|
+
});
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
### `postFormData`
|
|
544
|
+
|
|
545
|
+
POST a `multipart/form-data` payload. Prefer `uploadConversionFile` for file uploads.
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
postFormData(path: string, formData: FormData): Promise<SubmitResponse>
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
### `uploadConversionFile`
|
|
554
|
+
|
|
555
|
+
Upload a file to a DataConversion endpoint. Wraps `postFormData`.
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
uploadConversionFile(params: {
|
|
559
|
+
path: string;
|
|
560
|
+
fileName: string;
|
|
561
|
+
fileContent: Blob | Buffer | Uint8Array | ArrayBuffer;
|
|
562
|
+
fileFieldName?: string; // default 'file'
|
|
563
|
+
fields?: Record<string, string>;
|
|
564
|
+
}): Promise<SubmitResponse>
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
import { readFileSync } from 'node:fs';
|
|
569
|
+
|
|
570
|
+
const fileBytes = readFileSync('patients.xlsx');
|
|
571
|
+
const response = await client.uploadConversionFile({
|
|
572
|
+
path: client.conversionUploadPath(ctx, 'qvet', 'xlsx'),
|
|
573
|
+
fileName: 'patients.xlsx',
|
|
574
|
+
fileContent: fileBytes,
|
|
575
|
+
});
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
### `pollBatchResponse`
|
|
581
|
+
|
|
582
|
+
Poll a `_batch-response` / `_search-response` path with a `thid`. Returns raw status + body.
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
pollBatchResponse(path: string, request: AsyncPollRequest): Promise<{ status: number; body: unknown }>
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
```ts
|
|
589
|
+
const { status, body } = await client.pollBatchResponse(
|
|
590
|
+
client.individualTaskPollPath(ctx),
|
|
591
|
+
{ thid: 'task-abc123' },
|
|
592
|
+
);
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
### `submitAndPoll`
|
|
598
|
+
|
|
599
|
+
Combines `submitBatch` + `pollUntilComplete` in a single call. The most common transport pattern.
|
|
600
|
+
|
|
601
|
+
```ts
|
|
602
|
+
submitAndPoll(
|
|
603
|
+
submitPath: string,
|
|
604
|
+
pollPath: string,
|
|
605
|
+
payload: unknown,
|
|
606
|
+
options?: PollOptions,
|
|
607
|
+
): Promise<SubmitAndPollResult>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Default poll options: `timeoutMs: 20_000`, `intervalMs: 1_000`.
|
|
611
|
+
|
|
612
|
+
```ts
|
|
613
|
+
const result = await client.submitAndPoll(
|
|
614
|
+
client.individualFamilyOrganizationBatchPath(ctx),
|
|
615
|
+
client.individualFamilyOrganizationPollPath(ctx),
|
|
616
|
+
payload,
|
|
617
|
+
{ timeoutMs: 30_000, intervalMs: 500 },
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
console.log(result.submit.status); // 202
|
|
621
|
+
console.log(result.poll.status); // 200
|
|
622
|
+
console.log(result.poll.body);
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
### `pollUntilComplete`
|
|
628
|
+
|
|
629
|
+
Polls a path until the server returns a non-202 status, or timeout is reached.
|
|
630
|
+
|
|
631
|
+
```ts
|
|
632
|
+
pollUntilComplete(
|
|
633
|
+
path: string,
|
|
634
|
+
request: AsyncPollRequest,
|
|
635
|
+
options?: PollOptions,
|
|
636
|
+
): Promise<PollResult>
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
```ts
|
|
640
|
+
const poll = await client.pollUntilComplete(
|
|
641
|
+
client.individualTaskPollPath(ctx),
|
|
642
|
+
{ thid: 'task-abc123' },
|
|
643
|
+
{ timeoutMs: 15_000 },
|
|
644
|
+
);
|
|
645
|
+
console.log(poll.status, poll.attempts);
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## High-level helpers
|
|
651
|
+
|
|
652
|
+
### `createPhoneReminderTasks`
|
|
653
|
+
|
|
654
|
+
Creates one reminder `Task` per reminder window via `individual/Task/_batch`.
|
|
655
|
+
|
|
656
|
+
Each window maps to one deterministic task ID (SHA-256 of routing context + refs + `remindAt`).
|
|
657
|
+
|
|
658
|
+
```ts
|
|
659
|
+
createPhoneReminderTasks(
|
|
660
|
+
ctx: RouteContext,
|
|
661
|
+
input: CreatePhoneReminderTasksInput,
|
|
662
|
+
options?: PollOptions,
|
|
663
|
+
): Promise<SubmitAndPollResult>
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
```ts
|
|
667
|
+
const result = await client.createPhoneReminderTasks(ctx, {
|
|
668
|
+
windows: [
|
|
669
|
+
{ offsetMinutes: 10080, remindAt: '2026-05-03T10:00:00.000Z' }, // 1 week before
|
|
670
|
+
{ offsetMinutes: 1440, remindAt: '2026-05-09T10:00:00.000Z' }, // 1 day before
|
|
671
|
+
{ offsetMinutes: 60, remindAt: '2026-05-10T09:00:00.000Z' }, // 1 hour before
|
|
672
|
+
],
|
|
673
|
+
locale: 'es-ES',
|
|
674
|
+
notificationPhone: '+34611111111',
|
|
675
|
+
controllerPhone: '+34600000001',
|
|
676
|
+
subjectRef: 'Person/+34611111111',
|
|
677
|
+
ownerRef: 'RelatedPerson/+34600000001',
|
|
678
|
+
focusRef: 'Appointment/2026-05-10T10:00:00.000Z',
|
|
679
|
+
reminderSummary: '10/05 10:00 | Hospital San Juan | Consulta cardiología',
|
|
680
|
+
maxAttempts: 3,
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
console.log(result.poll.status); // 200 if all tasks created
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
### `searchFamilyOrganization`
|
|
689
|
+
|
|
690
|
+
Search for an existing family organization by controller phone + usualname. Returns `null` when not found.
|
|
691
|
+
|
|
692
|
+
```ts
|
|
693
|
+
searchFamilyOrganization(
|
|
694
|
+
ctx: RouteContext,
|
|
695
|
+
filters: { controllerPhone: string; usualname: string; birthDate?: string },
|
|
696
|
+
options?: PollOptions,
|
|
697
|
+
): Promise<FamilyOrganizationSummary | null>
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
```ts
|
|
701
|
+
const org = await client.searchFamilyOrganization(ctx, {
|
|
702
|
+
controllerPhone: '+34600000001',
|
|
703
|
+
usualname: 'Maria',
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
if (org === null) {
|
|
707
|
+
// not found → proceed with registration
|
|
708
|
+
} else if (org.status === 'already_exists') {
|
|
709
|
+
console.log(org.organizationId); // UUID of the existing org
|
|
710
|
+
} else if (org.status === 'resume_required') {
|
|
711
|
+
// pending → re-submit Order to activate
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## Standalone exports
|
|
718
|
+
|
|
719
|
+
### `createDidcommPlainMessage`
|
|
720
|
+
|
|
721
|
+
Builds a DIDComm plaintext message object with a random `jti` and `thid`.
|
|
722
|
+
|
|
723
|
+
```ts
|
|
724
|
+
import { createDidcommPlainMessage } from 'dataspace-client-sdk-node';
|
|
725
|
+
|
|
726
|
+
const payload = createDidcommPlainMessage({
|
|
727
|
+
iss: 'acme',
|
|
728
|
+
aud: 'did:web:api.acme.org',
|
|
729
|
+
body: {
|
|
730
|
+
data: [{ type: 'Task', resource: { ... } }],
|
|
731
|
+
},
|
|
732
|
+
});
|
|
733
|
+
// payload.jti, payload.thid are set automatically
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
```ts
|
|
737
|
+
createDidcommPlainMessage(params: {
|
|
738
|
+
iss: string;
|
|
739
|
+
aud: string;
|
|
740
|
+
type?: string; // default 'didcomm-plain'
|
|
741
|
+
thid?: string; // auto-generated UUID if omitted
|
|
742
|
+
body: Record<string, unknown>;
|
|
743
|
+
meta?: Record<string, unknown>;
|
|
744
|
+
}): DidcommPlainMessage
|
|
745
|
+
```
|