dataspace-client-sdk-node 0.2.0 → 0.2.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 +21 -351
- package/TODO_PROMPT_NEXT_STEPS.md +185 -0
- package/artifacts/update-smart-wallet.js +1016 -0
- package/docs/BACKEND_NODE_INTEGRATION.md +13 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,353 +1,23 @@
|
|
|
1
1
|
# dataspace-client-sdk-node
|
|
2
2
|
|
|
3
|
-
Node.js SDK to consume GW/UNID async DIDComm
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
1. ICA proof/verification (`_verify`, external to this SDK).
|
|
26
|
-
2. GW activation in host registry: `Organization/_activate`.
|
|
27
|
-
3. Offer/Order phase for legal organization onboarding (always; if amount is 0, no payment step).
|
|
28
|
-
4. Device onboarding (DCR): `identity/openid/Device/_dcr`.
|
|
29
|
-
5. Post-DCR token exchange / SMART authorization for protected API calls.
|
|
30
|
-
|
|
31
|
-
Node SDK helpers:
|
|
32
|
-
- `activateOrganizationInGatewayFromIcaProof(...)` (UC5.2)
|
|
33
|
-
- `activateEmployeeDeviceWithActivationCode(...)` (UC5.4)
|
|
34
|
-
- `authenticateBackendPkceAndExchange(...)` or `authenticateBackendSmartStandard(...)`
|
|
35
|
-
|
|
36
|
-
### 2) Personal Organization Onboarding (individual/family/subject)
|
|
37
|
-
|
|
38
|
-
Canonical order:
|
|
39
|
-
|
|
40
|
-
1. Personal/family registration: `individual/org.schema/Organization/_batch`.
|
|
41
|
-
2. Offer acceptance/order confirmation: `individual/org.schema/Order/_batch`.
|
|
42
|
-
3. Continue with consent + subject data workflows.
|
|
43
|
-
|
|
44
|
-
Node SDK helper:
|
|
45
|
-
- `bootstrapSubjectOrganizationIndex(...)` (UC5.1: registration + optional order confirmation)
|
|
46
|
-
|
|
47
|
-
See:
|
|
48
|
-
- `docs/DEVELOPER_USE_CASES.md` (UC5.1..UC5.7)
|
|
49
|
-
- `docs/E2E_BOOTSTRAP.md` (host activation bootstrap)
|
|
50
|
-
|
|
51
|
-
## Scope
|
|
52
|
-
- Generic async batch client (`_batch` + `_batch-response`) and JSON POST helper.
|
|
53
|
-
- Route builders that cover Swagger v1 route families:
|
|
54
|
-
- `host/registry`: `Organization _batch/_activate`, `Order`,
|
|
55
|
-
- `entity`: `Employee`,
|
|
56
|
-
- `identity`: `Device/_dcr`, `Token/_exchange`, `License/_issue`, SMART token, Firebase custom token,
|
|
57
|
-
- `individual`: `Organization`, `Order`, `Person (legacy)`, `Consent`, `Composition`, `Communication`, `RelatedPerson`, `Observation`, `Task`,
|
|
58
|
-
- `digitaltwin`: `Composition` (`org.hl7.fhir.api` and `org.hl7.fhir.r4`),
|
|
59
|
-
- debug UHC task endpoints: `_call-start`, `_logs`.
|
|
60
|
-
|
|
61
|
-
## Claims Placement Contract
|
|
62
|
-
- Canonical batch-entry claims location: `entry.resource.meta.claims`.
|
|
63
|
-
- Legacy compatibility location: `entry.meta.claims`.
|
|
64
|
-
- This SDK now emits both during migration; new consumers should read/write `resource.meta.claims`.
|
|
65
|
-
|
|
66
|
-
## Install (local workspace)
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
cd tools/dataspace-client-sdk-node
|
|
70
|
-
npm install
|
|
71
|
-
npm run type-check
|
|
72
|
-
npm run build
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Tests (mocked, no network)
|
|
76
|
-
|
|
77
|
-
The SDK includes mocked tests (Python-SDK style) for:
|
|
78
|
-
- route/path building,
|
|
79
|
-
- async `submit + poll`,
|
|
80
|
-
- multipart conversion upload.
|
|
81
|
-
|
|
82
|
-
Run:
|
|
83
|
-
```bash
|
|
84
|
-
cd sdk/dataspace-client-sdk-node
|
|
85
|
-
|
|
86
|
-
npm test
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
import { DataspaceNodeClient, createDidcommPlainMessage } from './dist/index.js';
|
|
93
|
-
const client = new DataspaceNodeClient({
|
|
94
|
-
baseUrl: 'http://localhost:3000',
|
|
95
|
-
bearerToken: 'demo-token',
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const ctx = { tenantId: 'acme', jurisdiction: 'ES', sector: 'health-care' };
|
|
99
|
-
iss: 'adult1@example.com',
|
|
100
|
-
aud: 'did:web:api.acme.org',
|
|
101
|
-
body: {
|
|
102
|
-
data: [
|
|
103
|
-
{
|
|
104
|
-
type: 'Family-registration-form-v1.0',
|
|
105
|
-
meta: {
|
|
106
|
-
claims: {
|
|
107
|
-
'@context': 'org.schema',
|
|
108
|
-
'@type': 'template',
|
|
109
|
-
'org.schema.Organization.address.addressCountry': 'ES',
|
|
110
|
-
'org.schema.Organization.identifier.additionalType': 'UUID',
|
|
111
|
-
'org.schema.Organization.identifier.value': 'f0d4b66d-7e28-4fa2-91b7-7041e57f4f90',
|
|
112
|
-
'org.schema.Person.email': 'adult1@example.com',
|
|
113
|
-
'org.schema.Service.category': 'health-care',
|
|
114
|
-
'org.schema.Service.identifier': 'did:web:api-provider.example.com',
|
|
115
|
-
'org.schema.Service.serviceType': 'http://terminology.hl7.org/CodeSystem/v3-ActReason|SRVC',
|
|
116
|
-
'org.schema.Service.termsOfService': 'https://provider.example.com/terms',
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
],
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const submitPath = client.individualFamilyOrganizationBatchPath(ctx);
|
|
125
|
-
const pollPath = client.individualFamilyOrganizationPollPath(ctx);
|
|
126
|
-
const result = await client.submitAndPoll(submitPath, pollPath, payload);
|
|
127
|
-
console.log(result.poll.status, result.poll.body);
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Backend auth: identity-exchange.v1 (B2B PKCE flow)
|
|
131
|
-
|
|
132
|
-
For server-to-server integration (e.g. `uhc-unid-chat-node` calling the GW), the SDK implements the
|
|
133
|
-
full `identity-exchange.v1` flow: DCR binding → PKCE code → token → SMART bearer exchange.
|
|
134
|
-
|
|
135
|
-
This is the Node equivalent of Python's `authenticate_backend_pkce_and_exchange` in `connector-sdk-py`.
|
|
136
|
-
|
|
137
|
-
**Prerequisites:**
|
|
138
|
-
1. Your tenant org is activated in the GW (`registry/org.schema/Organization/_activate` with ICA VC).
|
|
139
|
-
2. An API key with the required scopes has been issued by ICA (`identity/api-key/_create`).
|
|
140
|
-
3. You have your service's public JWK (EC P-384 recommended).
|
|
141
|
-
|
|
142
|
-
**Usage:**
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
import { DataspaceNodeClient } from './dist/index.js';
|
|
146
|
-
|
|
147
|
-
const client = new DataspaceNodeClient({ baseUrl: 'https://gw.example.com' });
|
|
148
|
-
|
|
149
|
-
const ctx = { tenantId: 'acme', jurisdiction: 'ES', sector: 'health-care' };
|
|
150
|
-
|
|
151
|
-
// Run once per key pair; result is cached automatically.
|
|
152
|
-
const auth = await client.authenticateBackendPkceAndExchange({
|
|
153
|
-
ctx,
|
|
154
|
-
apiKey: process.env.GW_API_KEY!,
|
|
155
|
-
controllerPublicJwk: JSON.parse(process.env.GW_PUBLIC_JWK!),
|
|
156
|
-
scopes: ['onboarding', 'family-registration', 'license-order'],
|
|
157
|
-
endpointId: 'chatbot-main', // cache key; re-auth on expiry is automatic
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
if (auth.status === 'failed') {
|
|
161
|
-
throw new Error(`Backend auth failed at step: ${auth.step}`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Use the bearer for subsequent requests:
|
|
165
|
-
const authedClient = new DataspaceNodeClient({
|
|
166
|
-
baseUrl: 'https://gw.example.com',
|
|
167
|
-
bearerToken: auth.accessToken,
|
|
168
|
-
});
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
**Demo / local bypass (never for production):**
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
// .env: SECURITY_MODE=demo GW_AUTH_BEARER=static-demo-token
|
|
175
|
-
const client = new DataspaceNodeClient({
|
|
176
|
-
baseUrl: process.env.BASE_URL!,
|
|
177
|
-
bearerToken: process.env.GW_AUTH_BEARER, // skip identity-exchange.v1 entirely
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## Backend auth: smart-backend.v1 (client_credentials + private_key_jwt)
|
|
182
|
-
|
|
183
|
-
For direct OAuth2 machine-to-machine flows (bypassing the PKCE device flow), use the
|
|
184
|
-
`smart-backend.v1` profile. The SDK signs the `client_assertion` JWT locally using an
|
|
185
|
-
in-memory ES384 wallet.
|
|
186
|
-
|
|
187
|
-
This is the Node equivalent of Python's `authenticate_backend_smart_standard` in
|
|
188
|
-
`connector-sdk-py`.
|
|
189
|
-
|
|
190
|
-
**Usage:**
|
|
191
|
-
|
|
192
|
-
```ts
|
|
193
|
-
import { DataspaceNodeClient, MemoryWalletProvider } from './dist/index.js';
|
|
194
|
-
|
|
195
|
-
const wallet = new MemoryWalletProvider();
|
|
196
|
-
|
|
197
|
-
// walletContext scopes the key pair. Use the service's logical identity.
|
|
198
|
-
const walletContext = { tenantId: 'service-a', jurisdiction: 'ES', sector: 'health-care' };
|
|
199
|
-
|
|
200
|
-
const client = new DataspaceNodeClient({
|
|
201
|
-
baseUrl: 'https://gw.example.com',
|
|
202
|
-
wallet,
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// On first call, authenticates. On subsequent calls within token TTL, returns cached.
|
|
206
|
-
const result = await client.authenticateBackendSmartStandard({
|
|
207
|
-
clientId: 'service-a',
|
|
208
|
-
scopes: ['system/*.read', 'system/*.write'],
|
|
209
|
-
walletContext,
|
|
210
|
-
// tokenUrl: optional absolute URL; defaults to `${baseUrl}/token`
|
|
211
|
-
// audience: optional; defaults to the resolved tokenUrl
|
|
212
|
-
// assertionTtlSeconds: optional; defaults to 300
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
if (result.status === 'failed') {
|
|
216
|
-
throw new Error(`smart-backend.v1 auth failed: HTTP ${result.statusCode}`);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const authedClient = new DataspaceNodeClient({
|
|
220
|
-
baseUrl: 'https://gw.example.com',
|
|
221
|
-
bearerToken: result.accessToken,
|
|
222
|
-
});
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**How it works internally:**
|
|
226
|
-
1. `MemoryWalletProvider` generates a dedicated EC P-384 key (`use: sig`, `alg: ES384`).
|
|
227
|
-
2. `signCompactJws(...)` produces the `client_assertion` JWT signed with that key.
|
|
228
|
-
3. A single `client_credentials` POST to the token endpoint returns the bearer.
|
|
229
|
-
4. The token is cached until 30s before expiry; subsequent calls return `status: 'cached'`.
|
|
230
|
-
|
|
231
|
-
## DIDComm encrypted (nested JWS-in-JWE)
|
|
232
|
-
|
|
233
|
-
For GW endpoints that require `application/didcomm-encrypted+json`, use `submitBatchEncrypted`.
|
|
234
|
-
This implements the nested JOSE pattern expected by the backend: sign first (ES384 compact JWS),
|
|
235
|
-
then encrypt (ML-KEM-768 + A256GCM compact JWE with `cty: JWS`).
|
|
236
|
-
|
|
237
|
-
Requires a wallet provider and the recipient's ML-KEM-768 encryption JWK (from GW
|
|
238
|
-
`.well-known/jwks.json`, `use: enc`). The `MemoryWalletProvider` generates ML-KEM-768 keys
|
|
239
|
-
automatically — no RSA setup required.
|
|
240
|
-
|
|
241
|
-
### ML-KEM-768 JWK format
|
|
242
|
-
|
|
243
|
-
Encryption keys use the OKP JWK type with `crv: "ML-KEM-768"`:
|
|
244
|
-
|
|
245
|
-
```json
|
|
246
|
-
{
|
|
247
|
-
"kty": "OKP",
|
|
248
|
-
"crv": "ML-KEM-768",
|
|
249
|
-
"use": "enc",
|
|
250
|
-
"alg": "ML-KEM-768",
|
|
251
|
-
"x": "<base64url-encoded 1184-byte public key>",
|
|
252
|
-
"kid": "wallet:acme:ES:health-care:abc123"
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
The `encrypted_key` slot in the compact JWE is the 1088-byte ML-KEM ciphertext (base64url).
|
|
257
|
-
The 32-byte shared secret derived by KEM encapsulation is used directly as the AES-256-GCM CEK.
|
|
258
|
-
|
|
259
|
-
```ts
|
|
260
|
-
import { DataspaceNodeClient, MemoryWalletProvider } from './dist/index.js';
|
|
261
|
-
|
|
262
|
-
const wallet = new MemoryWalletProvider();
|
|
263
|
-
const walletContext = { tenantId: 'acme', jurisdiction: 'ES', sector: 'health-care' };
|
|
264
|
-
const client = new DataspaceNodeClient({ baseUrl: 'https://gw.example.com', wallet });
|
|
265
|
-
|
|
266
|
-
// Wallet's own ML-KEM enc JWK (share with backend so it can encrypt to you):
|
|
267
|
-
const [, encJwk] = await wallet.getPublicJwks(walletContext);
|
|
268
|
-
|
|
269
|
-
// Fetch GW encryption JWK from well-known endpoint for outbound encryption:
|
|
270
|
-
// const { keys } = await (await fetch('https://gw.example.com/.well-known/jwks.json')).json();
|
|
271
|
-
// const recipientEncJwk = keys.find(k => k.use === 'enc' && k.crv === 'ML-KEM-768');
|
|
272
|
-
|
|
273
|
-
// For local roundtrip test, use wallet's own enc key as recipient:
|
|
274
|
-
const recipientEncJwk = encJwk;
|
|
275
|
-
|
|
276
|
-
const payload = { thid: 'my-thid', body: { data: [] } };
|
|
277
|
-
const result = await client.submitBatchEncrypted(
|
|
278
|
-
client.individualFamilyOrganizationBatchPath(ctx),
|
|
279
|
-
payload,
|
|
280
|
-
recipientEncJwk,
|
|
281
|
-
walletContext,
|
|
282
|
-
);
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
**Cache helper** — if you need the current bearer without re-running the flow:
|
|
286
|
-
|
|
287
|
-
```ts
|
|
288
|
-
const bearer = client.getCachedBearerToken('chatbot-main');
|
|
289
|
-
// Returns undefined if not cached or expired (>30s remaining).
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
Full runnable example: `examples/backend-pkce-auth.mjs`
|
|
293
|
-
|
|
294
|
-
## Swagger parity strategy
|
|
295
|
-
- For any v1 route exposed in Swagger, use:
|
|
296
|
-
- `client.v1Path(ctx, section, format, resourceType, action)` for tenant routes.
|
|
297
|
-
- `client.hostRegistryPath(ctx, resourceType, action)` for host registry routes.
|
|
298
|
-
- Then call one of:
|
|
299
|
-
- `submitBundle(path, didcommPayload)` for DIDComm bundle submit routes (preferred),
|
|
300
|
-
- `submitBatch(path, didcommPayload)` (legacy alias, kept for compatibility),
|
|
301
|
-
- `submitLegacyJson(path, payload)` for non-DIDComm JSON routes,
|
|
302
|
-
- `pollBatchResponse(path, { thid })` / `pollUntilComplete(...)`,
|
|
303
|
-
- `postJson(path, payload)` for non-batch JSON routes.
|
|
304
|
-
|
|
305
|
-
This avoids hardcoding curl scripts per endpoint.
|
|
306
|
-
|
|
307
|
-
## Notes for telephony tests
|
|
308
|
-
- Keep GW/UHC unit/integration tests direct (service/router level).
|
|
309
|
-
- Use this SDK for consumer-style E2E tests and external Node.js service integrations.
|
|
310
|
-
- If individual onboarding moves to a separate service, telephony tests should consume that service and only use GW/UHC for reminders/calls.
|
|
311
|
-
|
|
312
|
-
## DataConversion / Excel
|
|
313
|
-
|
|
314
|
-
This SDK now includes conversion helpers:
|
|
315
|
-
- `conversionUploadPath(ctx, softwareId, sourceFormat)`
|
|
316
|
-
- `conversionUploadPollPath(ctx, softwareId, sourceFormat)`
|
|
317
|
-
- `uploadConversionFile({ path, fileName, fileContent, fields })`
|
|
318
|
-
|
|
319
|
-
Example:
|
|
320
|
-
- `examples/conversion-upload.mjs`
|
|
321
|
-
|
|
322
|
-
Run:
|
|
323
|
-
```bash
|
|
324
|
-
cd sdk/dataspace-client-sdk-node
|
|
325
|
-
npm run build
|
|
326
|
-
BASE_URL="http://localhost:3000" \
|
|
327
|
-
AUTH_BEARER="demo-token" \
|
|
328
|
-
TENANT_ID="acme" \
|
|
329
|
-
JURISDICTION="ES" \
|
|
330
|
-
SECTOR="animal-care" \
|
|
331
|
-
SOFTWARE_ID="excel-adapter" \
|
|
332
|
-
SOURCE_FORMAT="xlsx" \
|
|
333
|
-
SOURCE_FILE="/absolute/path/to/input.xlsx" \
|
|
334
|
-
node examples/conversion-upload.mjs
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
Notes:
|
|
338
|
-
- Exact multipart field names may vary by DataConversion deployment.
|
|
339
|
-
- If your conversion API is synchronous, polling is optional.
|
|
340
|
-
- If it is async, provide/resolve `thid` and poll `.../_upload-response`.
|
|
341
|
-
|
|
342
|
-
## Next planned additions
|
|
343
|
-
- Typed payload builders per flow (`family`, `relatedPerson`, `observation`, `task`).
|
|
344
|
-
- Claims mappers (`ClaimName` <-> SQL internal name with `_`).
|
|
345
|
-
- Retry/backoff + richer error mapping.
|
|
346
|
-
|
|
347
|
-
## Planning and Parity Docs
|
|
348
|
-
|
|
349
|
-
- TODO / execution prompt: `TODO_PROMPT_NEXT_STEPS.md`
|
|
350
|
-
- Node/Python API parity map: `SDK_PARITY_MAP.md`
|
|
351
|
-
|
|
352
|
-
## Pending Compatibility TODO
|
|
353
|
-
- See [SMART EHR compatibility TODO](docs/TODO_SMART_EHR_COMPAT.md).
|
|
3
|
+
Node.js SDK to consume GW/UNID async DIDComm endpoints.
|
|
4
|
+
|
|
5
|
+
## Documentation Index
|
|
6
|
+
|
|
7
|
+
1. [Full API Reference](docs/API.md)
|
|
8
|
+
2. [Data Model Alignment (GW + Chat + SDK)](docs/DATA_MODEL_ALIGNMENT.md)
|
|
9
|
+
3. [Frontend/Backend SDK Ownership Matrix](../docs/SDK_AUTH_OWNERSHIP.md)
|
|
10
|
+
4. [Developer Use-Case Cookbook (UC5 + additional patterns)](docs/DEVELOPER_USE_CASES.md)
|
|
11
|
+
5. [Live Local GW UC5 E2E (no mocks)](docs/E2E_LOCAL_GW_UC5.md)
|
|
12
|
+
6. [React Web Integration Guide](docs/REACT_WEB_INTEGRATION.md)
|
|
13
|
+
7. [Backend Node Integration Guide](docs/BACKEND_NODE_INTEGRATION.md)
|
|
14
|
+
8. [Controller Flow Step by Step](docs/CONTROLLER_FLOW_STEP_BY_STEP.md)
|
|
15
|
+
9. [Legal Organization Flow Step by Step](docs/LEGAL_ORGANIZATION_FLOW_STEP_BY_STEP.md)
|
|
16
|
+
10. [Practitioner Flow Step by Step](docs/PRACTITIONER_FLOW_STEP_BY_STEP.md)
|
|
17
|
+
11. [Portal Backend Integration Handover](docs/PORTAL_BACKEND_INTEGRATION_HANDOVER.md)
|
|
18
|
+
|
|
19
|
+
## TODO and Roadmap
|
|
20
|
+
|
|
21
|
+
1. [Prompt Next Steps TODO](TODO_PROMPT_NEXT_STEPS.md)
|
|
22
|
+
2. [SMART EHR Compatibility TODO](docs/TODO_SMART_EHR_COMPAT.md)
|
|
23
|
+
3. [SDK Parity Map](../SDK_PARITY_MAP.md)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# TODO / Prompt - Next Steps (dataspace-client-sdk-node)
|
|
2
|
+
|
|
3
|
+
Objetivo de este backlog:
|
|
4
|
+
- Mantener `dataspace-client-sdk-node` como SDK backend oficial para Node.
|
|
5
|
+
- Añadir una capa wallet/KMS reutilizable para clientes backend Node (paridad conceptual con Python).
|
|
6
|
+
- Evitar que servicios consumidores implementen crypto/auth ad-hoc fuera del SDK.
|
|
7
|
+
|
|
8
|
+
Importante (decisión de arquitectura actual):
|
|
9
|
+
- El wallet/KMS se implementa temporalmente dentro de este repo en:
|
|
10
|
+
- `src/sdk/dataspace-wallet-sdk-node/`
|
|
11
|
+
- Más adelante se extraerá a repo/npm independiente (`dataspace-wallet-sdk-node`) sin romper API.
|
|
12
|
+
|
|
13
|
+
## Repositorio fuente y referencias obligatorias
|
|
14
|
+
|
|
15
|
+
Estas son las fuentes que el agente debe tomar como referencia técnica antes de implementar:
|
|
16
|
+
|
|
17
|
+
1. Frontend / cliente app:
|
|
18
|
+
- `gdc-sdk-client-ts`
|
|
19
|
+
- Papel: SDK frontend/wallet UX-side (no backend custodial KMS).
|
|
20
|
+
|
|
21
|
+
2. Backend gateway template:
|
|
22
|
+
- `gwtemplate-node-ts`
|
|
23
|
+
- Ruta clave: `src/gdc-backend-utils-node`
|
|
24
|
+
- Papel: utilidades backend de crypto/KMS y contratos base.
|
|
25
|
+
|
|
26
|
+
3. Backend UNID (fork operativo):
|
|
27
|
+
- `gdc-unid-node-ts`
|
|
28
|
+
- Papel: integración real de GW + managers + KMS runtime + flujos de negocio.
|
|
29
|
+
|
|
30
|
+
4. SDK Python de referencia de paridad:
|
|
31
|
+
- `connector-sdk-py`
|
|
32
|
+
- Papel: referencia 1:1 de casos de uso backend.
|
|
33
|
+
|
|
34
|
+
5. Orquestador de canal (consumidor actual):
|
|
35
|
+
- `uhc-unid-chat-node`
|
|
36
|
+
- Papel: usa SDK de alto nivel; no debe contener crypto/KMS de backend.
|
|
37
|
+
|
|
38
|
+
Regla: si hay contradicción entre implementación Node actual y Python, documentar la divergencia y dejar TODO de convergencia.
|
|
39
|
+
|
|
40
|
+
## Contexto que el agente debe respetar
|
|
41
|
+
|
|
42
|
+
1. `uhc-unid-chat-node` y otros consumidores deben seguir usando métodos de alto nivel del SDK.
|
|
43
|
+
2. Los cambios internos de path builders de identidad son breaking solo para consumidores que montan rutas a mano.
|
|
44
|
+
3. Si el consumidor usa `authenticateBackendPkceAndExchange(...)`, no debe cambiar nada en su código por la migración de rutas identity.
|
|
45
|
+
|
|
46
|
+
## Funcionamiento actual de backend tools + KMS (baseline)
|
|
47
|
+
|
|
48
|
+
Resumen operativo esperado por el ecosistema backend:
|
|
49
|
+
|
|
50
|
+
1. Capa SDK cliente (`dataspace-client-sdk-node`):
|
|
51
|
+
- construye paths canónicos,
|
|
52
|
+
- hace submit/poll,
|
|
53
|
+
- orquesta auth backend (`_dcr -> _code -> _token -> _exchange`).
|
|
54
|
+
|
|
55
|
+
2. Capa backend utils / KMS (hoy en GW/template repos):
|
|
56
|
+
- `KmsService` / `DemoKmsService`,
|
|
57
|
+
- interfaces de crypto (`IKmsService`, tipos JWK/JWS/JWE),
|
|
58
|
+
- utilidades KEK/envelope para protección de claves y datos.
|
|
59
|
+
|
|
60
|
+
3. Capa GW backend (`gdc-unid-node-ts` / `gwtemplate-node-ts`):
|
|
61
|
+
- runtime multitenant,
|
|
62
|
+
- provisión y resolución de claves por tenant,
|
|
63
|
+
- operaciones de firma/verificación/cifrado en contexto servidor.
|
|
64
|
+
|
|
65
|
+
Límite de responsabilidad:
|
|
66
|
+
- `dataspace-client-sdk-node` no debe replicar managers de GW.
|
|
67
|
+
- Sí debe poder exponer wallet/KMS cliente reutilizable para backends no-GW.
|
|
68
|
+
|
|
69
|
+
## Definición de Hecho (DoD)
|
|
70
|
+
|
|
71
|
+
1. Existe módulo wallet interno funcional con interfaz pública estable.
|
|
72
|
+
2. El flujo `identity-exchange.v1` está soportado por métodos de alto nivel en Node (sin construir rutas manuales fuera del SDK).
|
|
73
|
+
3. Se documenta paridad Node/Python por capability (no solo por endpoint).
|
|
74
|
+
4. Hay tests que fallen si se rompe la paridad mínima acordada.
|
|
75
|
+
5. README y ejemplos permiten a otro equipo integrar sin leer código interno.
|
|
76
|
+
|
|
77
|
+
## Alcance técnico a implementar
|
|
78
|
+
|
|
79
|
+
### A) Wallet/KMS interno (nuevo)
|
|
80
|
+
|
|
81
|
+
Crear módulo en `src/sdk/dataspace-wallet-sdk-node/`:
|
|
82
|
+
|
|
83
|
+
- `types.ts`
|
|
84
|
+
- `WalletContext` (`tenantId`, `jurisdiction`, `sector`, opcional `walletId`)
|
|
85
|
+
- `PublicJwk`, `PrivateKeyRef`, `SignOptions`, `EncryptOptions`, `DecryptOptions`
|
|
86
|
+
- `WalletProviderKind = 'mem' | 'seed' | 'external'`
|
|
87
|
+
|
|
88
|
+
- `provider.ts`
|
|
89
|
+
- `WalletProvider` interface:
|
|
90
|
+
- `init(...)`
|
|
91
|
+
- `getPublicJwks(context)`
|
|
92
|
+
- `sign(payload, context, options)`
|
|
93
|
+
- `verify(payload, signature, jwk)`
|
|
94
|
+
- `encrypt(plaintext, recipientJwk, options)`
|
|
95
|
+
- `decrypt(ciphertext, context, options)`
|
|
96
|
+
|
|
97
|
+
- `providers/memory-provider.ts`
|
|
98
|
+
- provider mínimo productivo para pruebas.
|
|
99
|
+
|
|
100
|
+
- `providers/seed-provider.ts`
|
|
101
|
+
- solo para `demo/dev` (determinístico).
|
|
102
|
+
- prohibido recomendarlo para staging/prod.
|
|
103
|
+
|
|
104
|
+
- `WalletClient.ts`
|
|
105
|
+
- fachada single-tenant.
|
|
106
|
+
|
|
107
|
+
- `MultiWalletClient.ts`
|
|
108
|
+
- resolución por `tenantId/jurisdiction/sector`.
|
|
109
|
+
|
|
110
|
+
### B) Integración en `DataspaceNodeClient`
|
|
111
|
+
|
|
112
|
+
- Aceptar opcionalmente `wallet` en constructor/options.
|
|
113
|
+
- Mantener compatibilidad de los métodos actuales de negocio/auth.
|
|
114
|
+
- No mover lógica de dominios al wallet: wallet solo crypto/key operations.
|
|
115
|
+
|
|
116
|
+
### C) Auth de alto nivel (paridad Python)
|
|
117
|
+
|
|
118
|
+
Asegurar métodos de alto nivel para:
|
|
119
|
+
- `authenticateBackendPkceAndExchange(...)`
|
|
120
|
+
- base para `authenticateBackendSmartStandard(...)` (si el contrato backend ya está listo)
|
|
121
|
+
|
|
122
|
+
Notas:
|
|
123
|
+
- Internamente usar path builders canónicos nuevos.
|
|
124
|
+
- Evitar exponer helpers de rutas como API pública “recomendada” para auth.
|
|
125
|
+
|
|
126
|
+
## Plan de ejecución (orden obligatorio)
|
|
127
|
+
|
|
128
|
+
1. Fase 1 - Contratos y estructura
|
|
129
|
+
- Crear árbol `src/sdk/dataspace-wallet-sdk-node/*`.
|
|
130
|
+
- Definir interfaces y tipos.
|
|
131
|
+
- Añadir tests unitarios de contrato (sin integración GW todavía).
|
|
132
|
+
|
|
133
|
+
2. Fase 2 - Provider mem/seed
|
|
134
|
+
- Implementar `memory-provider` y `seed-provider`.
|
|
135
|
+
- Añadir tests de firma/verificación y cifrado/descifrado.
|
|
136
|
+
|
|
137
|
+
3. Fase 3 - Integración client
|
|
138
|
+
- Conectar wallet opcional en `src/client.ts`.
|
|
139
|
+
- Mantener sin breaking en usos actuales.
|
|
140
|
+
|
|
141
|
+
4. Fase 4 - Paridad y documentación
|
|
142
|
+
- Actualizar `SDK_PARITY_MAP.md` con estado real.
|
|
143
|
+
- Actualizar `README.md` con sección “Wallet/KMS for backend clients”.
|
|
144
|
+
- Añadir ejemplo runnable en `examples/`.
|
|
145
|
+
|
|
146
|
+
5. Fase 5 - Puerta de extracción futura
|
|
147
|
+
- Definir imports internos de forma que luego sea fácil reemplazar:
|
|
148
|
+
- `src/sdk/dataspace-wallet-sdk-node/*` -> paquete npm externo.
|
|
149
|
+
|
|
150
|
+
## Tests mínimos obligatorios
|
|
151
|
+
|
|
152
|
+
1. Unit tests wallet:
|
|
153
|
+
- sign/verify roundtrip
|
|
154
|
+
- encrypt/decrypt roundtrip
|
|
155
|
+
- error handling de context faltante
|
|
156
|
+
|
|
157
|
+
2. Unit tests auth orchestration:
|
|
158
|
+
- secuencia `_dcr -> _code -> _token -> _exchange`
|
|
159
|
+
- gestión de token cacheado vs refresh
|
|
160
|
+
|
|
161
|
+
3. Regression tests identity routes:
|
|
162
|
+
- verificar que internamente se usa patrón canónico
|
|
163
|
+
- `/{prefix}/cds-{j}/v1/{sector}/{tenantId}/identity/auth/{action}`
|
|
164
|
+
|
|
165
|
+
4. Public API smoke:
|
|
166
|
+
- import del SDK no rompe para consumidores actuales.
|
|
167
|
+
|
|
168
|
+
## Criterios de seguridad
|
|
169
|
+
|
|
170
|
+
- Ninguna private key en logs.
|
|
171
|
+
- `seed-provider` marcado explícitamente como no apto para staging/prod.
|
|
172
|
+
- Errores crypto sin volcar material sensible.
|
|
173
|
+
|
|
174
|
+
## Entregables esperados del agente
|
|
175
|
+
|
|
176
|
+
1. PR con código + tests + docs.
|
|
177
|
+
2. Resumen de decisiones (tradeoffs) en la descripción.
|
|
178
|
+
3. Tabla de estado actualizada en `SDK_PARITY_MAP.md`.
|
|
179
|
+
4. Lista de pendientes para extracción a repo independiente.
|
|
180
|
+
|
|
181
|
+
## Plantilla de commit sugerida
|
|
182
|
+
|
|
183
|
+
- `feat(wallet): add internal dataspace-wallet-sdk-node module (mem/seed providers)`
|
|
184
|
+
- `feat(auth): keep pkce high-level orchestration aligned with canonical identity routes`
|
|
185
|
+
- `docs(parity): update SDK parity map and wallet roadmap`
|