dataconv-client-sdk-ts 0.3.2 → 0.4.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 CHANGED
@@ -2,14 +2,39 @@
2
2
 
3
3
  TypeScript SDK for consuming the `adapter-ingestion-py` pre-conversion API.
4
4
 
5
- It includes:
6
-
7
- - tenant/software configuration creation and polling
5
+ ## Table of contents
6
+
7
+ - [DataConv Client SDK for TypeScript](#dataconv-client-sdk-for-typescript)
8
+ - [Table of contents](#table-of-contents)
9
+ - [Features](#features)
10
+ - [Installation](#installation)
11
+ - [Configuration](#configuration)
12
+ - [Discover form fields](#discover-form-fields)
13
+ - [Field selection tracking (UI dedup)](#field-selection-tracking-ui-dedup)
14
+ - [React example: multi-dropdown dedup](#react-example-multi-dropdown-dedup)
15
+ - [End-to-end flow](#end-to-end-flow)
16
+ - [Multipart / local file upload](#multipart--local-file-upload)
17
+ - [Backend initialization](#backend-initialization)
18
+ - [CLI](#cli)
19
+ - [Recommended local setup (no IP/DID flags in commands)](#recommended-local-setup-no-ipdid-flags-in-commands)
20
+ - [Command helper and endpoint-resolution conventions](#command-helper-and-endpoint-resolution-conventions)
21
+ - [One-shot evidence script](#one-shot-evidence-script)
22
+ - [Notes](#notes)
23
+
24
+ ---
25
+
26
+ ## Features
27
+
28
+ - Discover frontend field descriptors from `/.well-known/api-config.json`
29
+ - Track which fields have already been selected across UI dropdowns
30
+ - Tenant/software configuration creation and polling
8
31
  - Excel/XLSX upload via DIDComm attachment or `multipart/form-data`
9
32
  - `_upload-response` polling
10
- - promotion through `Composition/_patch` and `Patient/_batch`
11
- - tenant-scoped search under `/host/.../org.hl7.fhir.api/{resourceType}/_search`
12
- - helpers to read the converted `Bundle` and keep the last received response
33
+ - Promotion through `Composition/_patch` and `Patient/_batch`
34
+ - Tenant-scoped dataset search under `/publisher/.../dataset/{resourceType}/_search`
35
+ - Helpers to read the converted `Bundle` and keep the last received response
36
+
37
+ ---
13
38
 
14
39
  ## Installation
15
40
 
@@ -23,11 +48,161 @@ npm install dataconv-client-sdk-ts
23
48
  DATACONV_BASE_URL=http://localhost:8080
24
49
  ```
25
50
 
26
- ## Basic usage
51
+ ---
52
+
53
+ ## Discover form fields
54
+
55
+ The client reads the API discovery document published by the server and returns frontend-ready field descriptors.
56
+
57
+ ```ts
58
+ import { DataConvClient } from 'dataconv-client-sdk-ts';
59
+
60
+ const client = new DataConvClient({
61
+ issuerDid: 'did:web:clinic.example:employee:loader',
62
+ tenantId: 'VATES-B00000000',
63
+ jurisdiction: 'ES',
64
+ crypto: globalThis.crypto
65
+ });
66
+
67
+ const apiConfig = await client.getWellKnownApiConfig();
68
+
69
+ console.log(apiConfig.language); // "es"
70
+ console.log(apiConfig.fields);
71
+ // [
72
+ // { code: 'section', display: 'Departamento o sección: ...' },
73
+ // { code: 'coverage_insurer', display: 'Identificador o nombre de la aseguradora' }
74
+ // ]
75
+ ```
76
+
77
+ The returned object includes:
78
+
79
+ | Property | Type | Description |
80
+ |---|---|---|
81
+ | `language` | `string` | Language code of the API config (`"es"`, ...) |
82
+ | `fields` | `{ code, display }[]` | Ready-to-use options for dropdowns |
83
+ | `supportedFields` | `Record<string, string>` | Raw `code → display` map |
84
+ | `endpoints` | `Record<string, string>` | Endpoint paths for `create`, `upload`, etc. |
85
+
86
+ The recommended frontend flow is:
87
+
88
+ 1. Read `fields` from `getWellKnownApiConfig()`.
89
+ 2. Let the user map spreadsheet columns to those field codes.
90
+ 3. Submit `mappingConfig.fieldMap` using those same codes.
91
+
92
+ ---
93
+
94
+ ### Field selection tracking (UI dedup)
95
+
96
+ The SDK keeps a per-session set of already-selected field codes so the UI can prevent a user from assigning the same field to two different dropdowns.
97
+
98
+ | Method | Returns | Description |
99
+ |---|---|---|
100
+ | `selectField(code, mappedTo?)` | `boolean` | `true` if added, `false` if already selected |
101
+ | `unselectField(code)` | `boolean` | `true` if removed, `false` if not present |
102
+ | `isFieldSelected(code)` | `boolean` | Whether the code is currently selected |
103
+ | `getSelectedFieldCodes()` | `string[]` | All currently selected codes |
104
+ | `getSelectedFieldMappings()` | `Record<string, string>` | Map of selected field code → mapped source column |
105
+ | `getSelectedMappingForField(code)` | `string \| undefined` | Source column currently associated to the selected code |
106
+ | `clearSelectedFields()` | `void` | Reset selection state |
107
+
108
+ ```ts
109
+ client.selectField('section'); // true
110
+ client.selectField('section'); // false → already selected
111
+ client.selectField('concept', 'CONCEPTO');
112
+ client.getSelectedMappingForField('concept'); // 'CONCEPTO'
113
+ client.isFieldSelected('section'); // true
114
+ client.unselectField('section'); // true
115
+ client.getSelectedFieldCodes(); // []
116
+ ```
117
+
118
+ ---
27
119
 
28
- Minimum end-to-end flow:
120
+ ### React example: multi-dropdown dedup
29
121
 
30
- 1. Initialize the client and tokens.
122
+ ```tsx
123
+ import { useEffect, useMemo, useState } from 'react';
124
+ import { DataConvClient } from 'dataconv-client-sdk-ts';
125
+
126
+ const client = new DataConvClient({
127
+ issuerDid: 'did:web:clinic.example:employee:loader',
128
+ tenantId: 'VATES-B00000000',
129
+ jurisdiction: 'ES',
130
+ crypto: globalThis.crypto
131
+ });
132
+
133
+ type FieldOption = { code: string; display: string };
134
+
135
+ export function FieldMappingForm() {
136
+ const [options, setOptions] = useState<FieldOption[]>([]);
137
+ const [mapping, setMapping] = useState<Record<string, string>>({
138
+ colA: '',
139
+ colB: '',
140
+ colC: ''
141
+ });
142
+
143
+ useEffect(() => {
144
+ let mounted = true;
145
+ client.getSupportedFields().then((fields) => {
146
+ if (mounted) setOptions(fields);
147
+ });
148
+ return () => {
149
+ mounted = false;
150
+ client.clearSelectedFields();
151
+ };
152
+ }, []);
153
+
154
+ const selectedSet = useMemo(() => new Set(client.getSelectedFieldCodes()), [mapping]);
155
+
156
+ const onChangeField = (columnKey: string, newCode: string) => {
157
+ const previousCode = mapping[columnKey];
158
+ if (previousCode) {
159
+ client.unselectField(previousCode);
160
+ }
161
+
162
+ if (newCode && !client.selectField(newCode, columnKey)) {
163
+ const mappedTo = client.getSelectedMappingForField(newCode);
164
+ if (previousCode) {
165
+ client.selectField(previousCode);
166
+ }
167
+ alert(`El campo ${newCode} ya ha sido seleccionado${mappedTo ? ` en ${mappedTo}` : ''}.`);
168
+ return;
169
+ }
170
+
171
+ setMapping((current) => ({ ...current, [columnKey]: newCode }));
172
+ };
173
+
174
+ return (
175
+ <>
176
+ {Object.keys(mapping).map((columnKey) => (
177
+ <select
178
+ key={columnKey}
179
+ value={mapping[columnKey]}
180
+ onChange={(event) => onChangeField(columnKey, event.target.value)}
181
+ >
182
+ <option value="">Selecciona un campo</option>
183
+ {options.map((field) => {
184
+ const selectedInAnotherDropdown =
185
+ selectedSet.has(field.code) && mapping[columnKey] !== field.code;
186
+ return (
187
+ <option key={field.code} value={field.code} disabled={selectedInAnotherDropdown}>
188
+ {field.display}
189
+ </option>
190
+ );
191
+ })}
192
+ </select>
193
+ ))}
194
+ </>
195
+ );
196
+ }
197
+ ```
198
+
199
+ ---
200
+
201
+ ## End-to-end flow
202
+
203
+ Minimum steps to go from field discovery to promoted resources:
204
+
205
+ 1. Discover fields and initialize the client.
31
206
  2. Create the tenant/software configuration.
32
207
  3. Wait for `_create-response`.
33
208
  4. Upload the Excel file.
@@ -52,8 +227,6 @@ client.setVpToken('<vp_token>');
52
227
 
53
228
  // 1. Discover frontend field descriptors from the API.
54
229
  const apiConfig = await client.getWellKnownApiConfig();
55
-
56
- // Example UI options:
57
230
  const fieldOptions = apiConfig.fields;
58
231
  // [
59
232
  // { code: 'section', display: 'Departamento o sección: ...' },
@@ -135,6 +308,13 @@ const searchResponse = await client.searchResources({
135
308
  });
136
309
  ```
137
310
 
311
+ For DIDComm polling responses, the SDK also exposes:
312
+
313
+ - `getMainDiagnosticInfoByResponse(response)` — reads `OperationOutcome.issue[0].diagnostics` from a response.
314
+ - `getMainDiagnosticInfo()` — reads it from the last stored config/conversion response.
315
+
316
+ ---
317
+
138
318
  ## Multipart / local file upload
139
319
 
140
320
  ```ts
@@ -145,231 +325,200 @@ await client.uploadSpreadsheetMultipart({
145
325
  });
146
326
  ```
147
327
 
148
- ## CLI evidence for real upload + polling
328
+ ---
329
+
330
+ ## Backend initialization
149
331
 
150
- The package also exposes a CLI that performs a real upload call, waits for `_upload-response`, saves the full DIDComm response to JSON, and prints the main diagnostic summary.
332
+ If the backend instantiates the SDK after `Organization/_activate`, it can inject `axios` or `fetch`:
151
333
 
152
- ```bash
153
- dataconv-client \
154
- --service-did did:web:dataconv-api.example.org \
155
- --resolved-base-url http://127.0.0.1:8080 \
156
- --tenant-id demo-tenant \
157
- --software-id api-config \
158
- --resource-type Composition \
159
- --file ./examples/example-api-config.xlsx \
160
- --issuer-did did:web:organization.example.org:employee:loader \
161
- --authorization-bearer <token> \
162
- --output-json ./artifacts/appmypets-upload-response.json
334
+ ```ts
335
+ import axios from 'axios';
336
+ import { DataConvClient } from 'dataconv-client-sdk-ts';
337
+
338
+ const client = new DataConvClient({
339
+ issuerDid: activatedOrganizationDid,
340
+ tenantId: tenantAlternateName,
341
+ jurisdiction: 'ES',
342
+ httpClient: axios.create({ baseURL: process.env.DATACONV_BASE_URL }),
343
+ crypto: globalThis.crypto
344
+ });
345
+
346
+ client.setVpToken(vpTokenFromActivation);
347
+ ```
348
+
349
+ Also works with `fetch`:
350
+
351
+ ```ts
352
+ const client = new DataConvClient({
353
+ issuerDid: activatedOrganizationDid,
354
+ tenantId: tenantAlternateName,
355
+ jurisdiction: 'ES',
356
+ fetch,
357
+ crypto: globalThis.crypto
358
+ });
163
359
  ```
164
360
 
165
- The CLI prints:
361
+ ---
166
362
 
167
- - the exact public upload URL used
168
- - the Excel path and size in KB
169
- - the `Location` header returned by `_upload`
170
- - the `thid`
171
- - the exact polling URL used
172
- - the output JSON file path
173
- - the main diagnostic text from the final DIDComm response
363
+ ## CLI
174
364
 
175
- This is useful when you need a reproducible console trace for a justification dossier without pasting the whole JSON response into the report.
365
+ The package exposes a CLI that can first create mapping config, then upload a file, wait for `_upload-response`, save the full DIDComm response to JSON, and print the main outcome summary.
176
366
 
177
- When `--service-did` is used, the CLI can resolve it locally by either:
367
+ ### Local setup
178
368
 
179
- - passing `--resolved-base-url <url>`
180
- - or defining `DATACONV_SERVICE_DID_MAP` as a JSON object, for example:
369
+ Copy `.env.example` to `.env.local`, fill in your values, and source it before running commands:
181
370
 
182
371
  ```bash
183
- export DATACONV_SERVICE_DID_MAP='{"did:web:dataconv-api.example.org":"http://127.0.0.1:8080"}'
372
+ cp .env.example .env.local
373
+ # edit .env.local: tenantId, issuerDid, base URL, DATACONV_ID_TOKEN
374
+ source .env.local
184
375
  ```
185
376
 
186
- This keeps public examples neutral while still allowing local or temporary endpoint resolution outside the repository.
187
-
188
- ## Discover form fields from `/.well-known/api-config.json`
377
+ The helper script `scripts/evidencia-publicacion.sh` loads `.env.local` automatically (falls back to `.env.example`).
189
378
 
190
- The client can read the API discovery document published by the server and return frontend-ready field descriptors.
379
+ For advanced DID document-based endpoint resolution and full command reference, see [docs/cli-reference.md](docs/cli-reference.md).
191
380
 
192
- ```ts
193
- const apiConfig = await client.getWellKnownApiConfig();
381
+ ```bash
382
+ # 1) login against your IdP (store OIDC id_token locally)
383
+ dataconv login --id-token "$DATACONV_ID_TOKEN"
194
384
 
195
- console.log(apiConfig.language); // "es"
196
- console.log(apiConfig.fields);
197
- // [
198
- // { code: 'section', display: 'Departamento o sección: ...' },
199
- // { code: 'coverage_insurer', display: 'Identificador o nombre de la aseguradora' }
200
- // ]
385
+ # 2) exchange Bearer access token
386
+ dataconv exchange --scope "excel/_upload Subject/_search ChargeItem/_search DocumentReference/_search"
201
387
 
202
- const supportedFields = await client.getSupportedFields();
388
+ # 3) optional tenant-admin step: create a constrained API key
389
+ dataconv api-key-create --email ops@example.com --target "publisher/cds-es/v1/animal-care/vates-a00000001/dataset/*/*/_upload"
203
390
 
204
- // Optional: track selection state for UI dropdown dedup checks.
205
- if (!client.selectField('section')) {
206
- alert('Campo "section" ya seleccionado en otro dropdown');
207
- }
208
- if (!client.selectField('section')) {
209
- alert('No puedes seleccionar el mismo campo dos veces');
210
- }
391
+ # 4) upload + automatic polling
392
+ dataconv upload ./examples/example-api-config.xlsx \
393
+ --output-json ./artifacts/upload-response.json
211
394
 
212
- const uploadResponse = await client.uploadSpreadsheetAndWait(
213
- 'https://example.com/AppMyPets-api-config.xlsx?dl=1',
214
- {
215
- softwareId: 'api-config',
216
- resourceType: 'Composition',
217
- fileName: 'AppMyPets-api-config.xlsx'
218
- }
219
- );
395
+ # 5) optional: patch/batch after review, then search with Bearer token
396
+ dataconv search --resource-type DocumentReference --params '{"_count": 5}'
220
397
 
221
- const summaryText = client.getMainDiagnosticInfoByResponse(uploadResponse);
222
- console.log(summaryText);
398
+ # optional alternative to patch
399
+ dataconv batch --thid "<thid-obtenido-de-upload>"
223
400
  ```
224
401
 
225
- The returned object includes:
402
+ Output includes:
226
403
 
227
- - `language`
228
- - `supportedFields` as raw `code -> display`
229
- - `fields` as `{ code, display }[]`
230
- - `endpoints` for `create`, `createResponse`, `upload`, and `uploadResponse`
404
+ - exact public upload URL used
405
+ - Excel path and size in KB
406
+ - `Location` header from `_upload`
407
+ - `thid`
408
+ - exact polling URL used
409
+ - output JSON file path
410
+ - main `OperationOutcome.issue[0].description` when available (fallback: `diagnostics`)
231
411
 
232
- For DIDComm polling responses, the SDK also exposes:
412
+ When `--mapping-json` is provided to `upload`, CLI creates tenant mapping config first and polls `config/_create-response` before submitting the spreadsheet.
233
413
 
234
- - `getMainDiagnosticInfoByResponse(response)` to read the main `OperationOutcome.issue[0].diagnostics`
235
- - `getMainDiagnosticInfo()` to read it from the last stored config/conversion response
414
+ The CLI prints evidence-style process logs, for example:
236
415
 
237
- The recommended frontend flow is:
416
+ - authentication/exchange against configured dataspace name
417
+ - upload accepted with `thid`
418
+ - automatic `_upload-response` polling
419
+ - final summary and JSON artifact path
238
420
 
239
- 1. Read `fields` from `/.well-known/api-config.json`.
240
- 2. Let the user map spreadsheet columns to those field codes.
241
- 3. Submit `mappingConfig.fieldMap` using those same codes.
421
+ ### Command helper and endpoint-resolution conventions
242
422
 
243
- ### React example: avoid duplicate field selection across dropdowns
423
+ Use per-command help to see expected conventions:
244
424
 
245
- ```tsx
246
- import { useEffect, useMemo, useState } from 'react';
247
- import { DataConvClient } from 'dataconv-client-sdk-ts';
425
+ ```bash
426
+ dataconv help exchange
427
+ dataconv help upload
428
+ dataconv search --help
429
+ ```
248
430
 
249
- const client = new DataConvClient({
250
- issuerDid: 'did:web:clinic.example:employee:loader',
251
- tenantId: 'VATES-B00000000',
252
- jurisdiction: 'ES',
253
- crypto: globalThis.crypto
254
- });
431
+ Service IDs used as CLI resolution metadata:
255
432
 
256
- type FieldOption = { code: string; display: string };
433
+ - `exchange`: `#identity:openid:token:_exchange`
434
+ - `upload` (update): `#dataset:{softwareId}:{resourceType}:_upload`
435
+ - `patch` (publish): `#dataset:{softwareId}:{resourceType}:_patch`
436
+ - `batch` (publish): `#dataset:{softwareId}:{resourceType}:_batch`
437
+ - `search`: `#dataset:api:{resourceType}:_search`
257
438
 
258
- export function FieldMappingForm() {
259
- const [options, setOptions] = useState<FieldOption[]>([]);
260
- const [mapping, setMapping] = useState<Record<string, string>>({
261
- colA: '',
262
- colB: '',
263
- colC: ''
264
- });
439
+ Fallback env vars for localhost testing:
265
440
 
266
- useEffect(() => {
267
- let mounted = true;
268
- client.getSupportedFields().then((fields) => {
269
- if (mounted) setOptions(fields);
270
- });
271
- return () => {
272
- mounted = false;
273
- client.clearSelectedFields();
274
- };
275
- }, []);
441
+ - `PUBLISHER_OPENID_EXCHANGE`
442
+ - `PUBLISHER_DATASET_UPDATE`
443
+ - `PUBLISHER_DATASET_PATCH`
444
+ - `PUBLISHER_DATASET_BATCH`
445
+ - `PUBLISHER_DATASET_SEARCH`
276
446
 
277
- const selectedSet = useMemo(() => new Set(client.getSelectedFieldCodes()), [mapping]);
447
+ Important contract note:
278
448
 
279
- const onChangeField = (columnKey: string, newCode: string) => {
280
- const previousCode = mapping[columnKey];
281
- if (previousCode) {
282
- client.unselectField(previousCode);
283
- }
449
+ - `--organization-did` and `--service-id` are stored as CLI-side endpoint-resolution context.
450
+ - The `/exchange` request body remains OpenAPI-compatible (no extra payload fields derived from service-id/fallback metadata).
284
451
 
285
- if (newCode && !client.selectField(newCode)) {
286
- if (previousCode) {
287
- client.selectField(previousCode);
288
- }
289
- alert(`El campo ${newCode} ya ha sido seleccionado anteriormente.`);
290
- return;
291
- }
452
+ ### One-shot evidence script
292
453
 
293
- setMapping((current) => ({ ...current, [columnKey]: newCode }));
294
- };
454
+ Use the included helper to run login/exchange/upload/search in one shot:
295
455
 
296
- return (
297
- <>
298
- {Object.keys(mapping).map((columnKey) => (
299
- <select
300
- key={columnKey}
301
- value={mapping[columnKey]}
302
- onChange={(event) => onChangeField(columnKey, event.target.value)}
303
- >
304
- <option value="">Selecciona un campo</option>
305
- {options.map((field) => {
306
- const selectedInAnotherDropdown =
307
- selectedSet.has(field.code) && mapping[columnKey] !== field.code;
308
- return (
309
- <option key={field.code} value={field.code} disabled={selectedInAnotherDropdown}>
310
- {field.display}
311
- </option>
312
- );
313
- })}
314
- </select>
315
- ))}
316
- </>
317
- );
318
- }
456
+ ```bash
457
+ chmod +x ./scripts/publish-dataset.sh
458
+ ./scripts/evidencia-publicacion.sh
459
+
460
+ # opcional: forzar mapping JSON externo + promoción por batch
461
+ DATACONV_PUBLICACION_MAPPING_JSON=./examples/mappings/qvet-v1.json \
462
+ DATACONV_PUBLICACION_HEADER_ROW_INDEX=1 \
463
+ DATACONV_PROMOTION_MODE=batch \
464
+ ./scripts/evidencia-publicacion.sh
319
465
  ```
320
466
 
321
- In this pattern:
322
-
323
- - `selectField(code)` returns `false` when the code was already used.
324
- - `unselectField(code)` frees a code when a dropdown changes value.
325
- - `getSelectedFieldCodes()` helps disable options already selected elsewhere.
326
-
327
- ## Backend initialization
467
+ Generated files:
328
468
 
329
- If the backend instantiates the SDK after `Organization/_activate`, it can inject `axios` or `fetch` just like `ica-client-sdk-ts`.
469
+ - `./artifacts/datasets/upload-response.json`
470
+ - `./artifacts/datasets/search-subject.json`
471
+ - `./artifacts/datasets/search-documentreference.json`
472
+ - `./artifacts/datasets/dcat-files.json`
330
473
 
331
- ```ts
332
- import axios from 'axios';
333
- import { DataConvClient } from 'dataconv-client-sdk-ts';
474
+ Notes on scope model and flow:
334
475
 
335
- const httpClient = axios.create({
336
- baseURL: process.env.DATACONV_BASE_URL
337
- });
476
+ - You can request endpoint-action scopes (recommended for evaluator logs), e.g. `excel/_upload` or `DocumentReference/_search`.
477
+ - Backend accepts these action scopes as equivalent to coarse scopes (`dataconv.upload` / `dataconv.read`).
478
+ - `tenantId`, `jurisdiction`, `sector`, and `softwareId` are taken from env/profile defaults (recommended tenant format: `VATES-<NIF>`).
479
+ - API keys do **not** mint `id_token`s. The `id_token` always comes from the external IdP/login step.
480
+ - API keys are used at `/exchange` time to constrain or delegate scopes. The resulting Bearer `access_token` is what you use for config, upload, patch/batch, and search.
481
+ - For explicit exceptional non-confidential mode, send `api_key_profile=api-key-exception.v1` in `/exchange` payload (server must allow it).
482
+ - Recommended API key authorization model is atomic:
483
+ - one rule entry (`data[].resource`) = one consent-like authorization rule = one ODRL policy object.
484
+ - include `scope` (mandatory), and preferably `target` + `instrument` (ODRL).
338
485
 
339
- const client = new DataConvClient({
340
- issuerDid: activatedOrganizationDid,
341
- tenantId: tenantAlternateName,
342
- jurisdiction: 'ES',
343
- httpClient,
344
- crypto: globalThis.crypto
345
- });
486
+ When `--service-did` is used, resolve it locally with either `--resolved-base-url` or the `DATACONV_SERVICE_DID_MAP` env variable:
346
487
 
347
- client.setVpToken(vpTokenFromActivation);
488
+ ```bash
489
+ export DATACONV_SERVICE_DID_MAP='{"did:web:dataconv-api.example.org":"http://127.0.0.1:8080"}'
348
490
  ```
349
491
 
350
- It also works with `fetch`:
351
-
352
- ```ts
353
- const client = new DataConvClient({
354
- issuerDid: activatedOrganizationDid,
355
- tenantId: tenantAlternateName,
356
- jurisdiction: 'ES',
357
- fetch,
358
- crypto: globalThis.crypto
359
- });
360
- ```
492
+ > **DEMO_MODE** If the backend runs with `DEMO_MODE=true`, generate a test `id_token` without a real IdP:
493
+ >
494
+ > ```bash
495
+ > # genera un id_token demo (alg:none, solo requiere campo email en el payload)
496
+ > export DATACONV_ID_TOKEN=$(node -e '
497
+ > const h = Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url");
498
+ > const p = Buffer.from(JSON.stringify({email:"admin@example.com"})).toString("base64url");
499
+ > console.log(`${h}.${p}.`);
500
+ > ')
501
+ > # eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIn0.
502
+ > ```
503
+ >
504
+ > Use the token with `--authorization-bearer "$DATACONV_ID_TOKEN"`. No signature verification is performed in demo mode; only the `email` claim is required.
505
+
506
+ ---
361
507
 
362
508
  ## Notes
363
509
 
364
- - For configuration and conversion calls, the operational tenant identifier should be `tenantId`, typically the organization's VAT/taxId.
365
- - `sector` is variable and is part of the public route for config, digital twin, and search.
510
+ - `tenantId` is the operational tenant identifier, typically the organization's VAT/taxId.
511
+ - `sector` is part of the public route for publisher config, dataset publication, and dataset search.
366
512
  - `patchConversion()` defaults to `Composition/_patch`.
367
513
  - `batchPromotion()` defaults to `Patient/_batch`.
368
- - `searchResources()` resolves to `/host/cds-{jurisdiction}/v1/{sector}/{tenantId}/org.hl7.fhir.api/{resourceType}/_search`.
369
- - Parameter names sent by `searchResources()` are lowercase. Example: `userselected`, `date`.
370
- - Even if the caller passes `userSelected`, the SDK normalizes it to `userselected` before sending the body.
371
- - In `_search`, the current comparators are prefixed in the value: `ge2026-01-01`, `gt...`, `le...`, `lt...`.
372
- - The pre-conversion service can already require `vp_token` and/or `id_token` depending on `PRECONV_AUTH_MODE`, although it does not yet validate signatures or the full session exchange in `adapter-ingestion-py`.
373
- - The current backend still rejects `source_format=csv`; the SDK models it because the route exists, but real support today is Excel/XLSX.
374
- - `gdc-common-utils-ts` is consumed from npm; this SDK adds the concrete pre-conversion types on top of those DIDComm helpers.
375
- - ICA VCs and `controller.publicKeyJwk` belong to the backend onboarding/`_activate` flow. `DataConvClient` is instantiated afterwards, once the tenant is already activated and only pre-conversion calls are needed.
514
+ - `searchResources()` resolves to `/publisher/cds-{jurisdiction}/v1/{sector}/{tenantId}/dataset/{resourceType}/_search`.
515
+ - Search parameter names are normalized to lowercase (`userSelected` `userselected`).
516
+ - Search comparators are prefixed in the value: `ge2026-01-01`, `gt...`, `le...`, `lt...`.
517
+ - The backend may require `vp_token` and/or `id_token` depending on `PRECONV_AUTH_MODE`.
518
+ - CSV upload is modeled in the SDK but the current backend only accepts Excel/XLSX.
519
+ - `gdc-common-utils-ts` is an npm dependency; this SDK adds concrete pre-conversion types on top of those DIDComm helpers.
520
+ - ICA VCs and `controller.publicKeyJwk` belong to the `_activate` onboarding flow. `DataConvClient` is used afterwards, once the tenant is already activated.
521
+
522
+ ## Roadmap and Briefing
523
+ - `BRIEFING_DATASPACE_EN.md`
524
+ - `TODO_ROADMAP.md`
@@ -1,4 +1,4 @@
1
- import type { DataConvBatchOptions, ConversionResultEntry, ConvertedBundleResource, CreateTenantConfigOptions, DataConvClientConfig, DataConvConversionPollOptions, DataConvCreateResult, DataConvDidCommResponse, DataConvMultipartUploadOptions, DataConvOperationOutcome, DataConvPatchOptions, DataConvPatchResponse, DataConvSearchBundle, DataConvSearchOptions, DataConvTenantConfigPollOptions, DataConvUploadDidCommOptions, DataConvUploadResult, DataConvSupportedField, DataConvWellKnownApiConfig, TenantAdapterConfigEntry, TenantAdapterConfigResource } from './types.js';
1
+ import type { DataConvBatchOptions, ConversionResultEntry, ConvertedBundleResource, CreateTenantConfigOptions, DataConvClientConfig, DataConvConversionPollOptions, DataConvCreateResult, DataConvDidCommResponse, DataConvApiKeyCreateActionsOptions, DataConvApiKeyCreateActionsResult, DataConvApiKeyAuthorizationRule, DataConvApiKeyLifecycleOptions, DataConvApiKeyLifecycleResult, DataConvExchangeTokenOptions, DataConvExchangeTokenResult, DataConvMultipartUploadOptions, DataConvOperationOutcome, DataConvOrganizationTenantActivationOptions, DataConvOrganizationTenantActivationResult, DataConvPatchOptions, DataConvPatchResponse, DataConvSearchBundle, DataConvSearchOptions, DataConvTenantConfigPollOptions, DataConvUploadDidCommOptions, DataConvUploadResult, DataConvSupportedField, DataConvWellKnownApiConfig, TenantAdapterConfigEntry, TenantAdapterConfigResource } from './types.js';
2
2
  export declare class DataConvClient {
3
3
  private readonly config;
4
4
  private readonly httpClient?;
@@ -13,24 +13,38 @@ export declare class DataConvClient {
13
13
  private lastTenantConfigResponse?;
14
14
  private lastConversionResponse?;
15
15
  private selectedFieldCodes;
16
+ private selectedFieldMappings;
16
17
  constructor(config: DataConvClientConfig);
17
18
  setIdToken(idToken: string): void;
18
19
  setVpToken(vpToken: string): void;
20
+ activateOrganizationTenant(options: DataConvOrganizationTenantActivationOptions): Promise<DataConvOrganizationTenantActivationResult>;
19
21
  getLastTenantConfigResponse(): DataConvDidCommResponse<TenantAdapterConfigResource> | undefined;
20
22
  getLastConversionResponse(): DataConvDidCommResponse<ConvertedBundleResource> | undefined;
21
23
  clearStoredResponses(): void;
24
+ exchangeToken(options: DataConvExchangeTokenOptions): Promise<DataConvExchangeTokenResult>;
25
+ createTenantApiKeyActions(options: DataConvApiKeyCreateActionsOptions): Promise<DataConvApiKeyCreateActionsResult>;
26
+ createTenantApiKeyRules(options: Omit<DataConvApiKeyCreateActionsOptions, 'actions'> & {
27
+ rules: DataConvApiKeyAuthorizationRule[];
28
+ }): Promise<DataConvApiKeyCreateActionsResult>;
29
+ disableTenantApiKeyActions(options: DataConvApiKeyLifecycleOptions): Promise<DataConvApiKeyLifecycleResult>;
30
+ removeTenantApiKeyActions(options: DataConvApiKeyLifecycleOptions): Promise<DataConvApiKeyLifecycleResult>;
31
+ private updateTenantApiKeyActions;
22
32
  getTenantConfigEntries(response?: DataConvDidCommResponse<TenantAdapterConfigResource> | undefined): Array<TenantAdapterConfigEntry<TenantAdapterConfigResource>>;
23
33
  getSuccessfulTenantConfigs(response?: DataConvDidCommResponse<TenantAdapterConfigResource> | undefined): TenantAdapterConfigResource[];
24
34
  getConversionEntry(response?: DataConvDidCommResponse<ConvertedBundleResource> | undefined): ConversionResultEntry | undefined;
25
35
  getConvertedBundle(response?: DataConvDidCommResponse<ConvertedBundleResource> | undefined): ConvertedBundleResource | undefined;
26
36
  getResponseIssues<TResource>(response: DataConvDidCommResponse<TResource> | undefined): DataConvOperationOutcome | undefined;
27
37
  getMainDiagnosticInfoByResponse<TResource>(response: DataConvDidCommResponse<TResource> | undefined): string | undefined;
38
+ getMainIssueDescriptionByResponse<TResource>(response: DataConvDidCommResponse<TResource> | undefined): string | undefined;
28
39
  getSelectedFieldCodes(): string[];
40
+ getSelectedFieldMappings(): Record<string, string>;
41
+ getSelectedMappingForField(code: string): string | undefined;
29
42
  isFieldSelected(code: string): boolean;
30
- selectField(code: string): boolean;
43
+ selectField(code: string, mappedTo?: string): boolean;
31
44
  unselectField(code: string): boolean;
32
45
  clearSelectedFields(): void;
33
46
  getMainDiagnosticInfo(): string | undefined;
47
+ getMainIssueDescription(): string | undefined;
34
48
  getWellKnownApiConfig(): Promise<DataConvWellKnownApiConfig>;
35
49
  getSupportedFields(): Promise<DataConvSupportedField[]>;
36
50
  createTenantConfig(options: CreateTenantConfigOptions): Promise<DataConvCreateResult>;