dataconv-client-sdk-ts 0.2.0 → 0.3.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.
- package/README.md +25 -4
- package/dist/DataConvClient.d.ts +3 -1
- package/dist/DataConvClient.d.ts.map +1 -1
- package/dist/DataConvClient.js +34 -0
- package/dist/DataConvClient.js.map +1 -1
- package/dist/claims.d.ts +27 -0
- package/dist/claims.d.ts.map +1 -0
- package/dist/claims.js +71 -0
- package/dist/claims.js.map +1 -0
- package/dist/client/excel-generator.d.ts +7 -0
- package/dist/client/excel-generator.d.ts.map +1 -0
- package/dist/client/excel-generator.js +34 -0
- package/dist/client/excel-generator.js.map +1 -0
- package/dist/field-maps.d.ts +37 -0
- package/dist/field-maps.d.ts.map +1 -0
- package/dist/field-maps.js +104 -0
- package/dist/field-maps.js.map +1 -0
- package/dist/i18n/es.d.ts +5 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +66 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +24 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -2
- package/.github/copilot-instructions.md +0 -104
- package/__mocks__/gdc-common-utils-ts/utils/didcomm.ts +0 -39
- package/jest.config.js +0 -16
- package/src/DataConvClient.ts +0 -567
- package/src/__tests__/DataConvClient.test.ts +0 -608
- package/src/client/constants.ts +0 -8
- package/src/client/helpers.ts +0 -127
- package/src/client/message.ts +0 -139
- package/src/index.ts +0 -39
- package/src/types.ts +0 -302
- package/tsconfig.json +0 -21
package/src/DataConvClient.ts
DELETED
|
@@ -1,567 +0,0 @@
|
|
|
1
|
-
import axios, { type AxiosInstance } from 'axios';
|
|
2
|
-
import { DEFAULT_SECTOR, DEFAULT_UPLOAD_BODY } from './client/constants.js';
|
|
3
|
-
import {
|
|
4
|
-
buildUrl,
|
|
5
|
-
createUuid,
|
|
6
|
-
headerValue,
|
|
7
|
-
headersToObject,
|
|
8
|
-
isFormData,
|
|
9
|
-
normalizeSearchParams,
|
|
10
|
-
normalizeSourceFormat,
|
|
11
|
-
requireText,
|
|
12
|
-
resolveConfigSoftwareId,
|
|
13
|
-
resolveConfigTenantId,
|
|
14
|
-
resolveJurisdiction,
|
|
15
|
-
resolveResourceType,
|
|
16
|
-
resolveSector,
|
|
17
|
-
resolveTenantId,
|
|
18
|
-
sleep
|
|
19
|
-
} from './client/helpers.js';
|
|
20
|
-
import { buildAttachment, buildEnvelope, buildMultipartFormData, buildUploadExtra } from './client/message.js';
|
|
21
|
-
import type {
|
|
22
|
-
DataConvBatchOptions,
|
|
23
|
-
ConversionResultEntry,
|
|
24
|
-
ConvertedBundleResource,
|
|
25
|
-
CreateTenantConfigOptions,
|
|
26
|
-
DataConvClientConfig,
|
|
27
|
-
DataConvConversionPollOptions,
|
|
28
|
-
DataConvCreateResult,
|
|
29
|
-
DataConvCrypto,
|
|
30
|
-
DataConvDidCommAttachment,
|
|
31
|
-
DataConvDidCommResponse,
|
|
32
|
-
DataConvMultipartUploadOptions,
|
|
33
|
-
DataConvOperationOutcome,
|
|
34
|
-
DataConvPatchOptions,
|
|
35
|
-
DataConvPatchResponse,
|
|
36
|
-
DataConvSearchBundle,
|
|
37
|
-
DataConvSearchOptions,
|
|
38
|
-
DataConvTenantConfigPollOptions,
|
|
39
|
-
DataConvUploadDidCommOptions,
|
|
40
|
-
DataConvUploadResult,
|
|
41
|
-
SourceFormat,
|
|
42
|
-
TenantAdapterConfigEntry,
|
|
43
|
-
TenantAdapterConfigResource
|
|
44
|
-
} from './types.js';
|
|
45
|
-
|
|
46
|
-
export class DataConvClient {
|
|
47
|
-
private readonly httpClient?: AxiosInstance;
|
|
48
|
-
private readonly fetchFn?: typeof fetch;
|
|
49
|
-
private readonly cryptoApi?: DataConvCrypto;
|
|
50
|
-
private readonly baseUrl: string;
|
|
51
|
-
private readonly retryTimes: number;
|
|
52
|
-
private readonly retryDelayMs: number;
|
|
53
|
-
private readonly defaultExpSeconds: number;
|
|
54
|
-
|
|
55
|
-
private idToken?: string;
|
|
56
|
-
private vpToken?: string;
|
|
57
|
-
private lastTenantConfigResponse?: DataConvDidCommResponse<TenantAdapterConfigResource>;
|
|
58
|
-
private lastConversionResponse?: DataConvDidCommResponse<ConvertedBundleResource>;
|
|
59
|
-
|
|
60
|
-
constructor(private readonly config: DataConvClientConfig) {
|
|
61
|
-
this.baseUrl = config.baseUrl || process.env.DATACONV_BASE_URL || 'http://localhost:8080';
|
|
62
|
-
this.fetchFn = config.fetch ?? (typeof fetch !== 'undefined' ? fetch : undefined);
|
|
63
|
-
this.cryptoApi = config.crypto ?? (globalThis as typeof globalThis & { crypto?: DataConvCrypto }).crypto;
|
|
64
|
-
this.httpClient = config.httpClient ?? (config.fetch ? undefined : axios.create({ baseURL: this.baseUrl }));
|
|
65
|
-
this.retryTimes = config.retryTimes ?? 10;
|
|
66
|
-
this.retryDelayMs = config.retryDelayMs ?? 1000;
|
|
67
|
-
this.defaultExpSeconds = config.defaultExpSeconds ?? 300;
|
|
68
|
-
this.idToken = config.idToken;
|
|
69
|
-
this.vpToken = config.vpToken;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
setIdToken(idToken: string): void {
|
|
73
|
-
this.idToken = idToken;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
setVpToken(vpToken: string): void {
|
|
77
|
-
this.vpToken = vpToken;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
getLastTenantConfigResponse(): DataConvDidCommResponse<TenantAdapterConfigResource> | undefined {
|
|
81
|
-
return this.lastTenantConfigResponse;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
getLastConversionResponse(): DataConvDidCommResponse<ConvertedBundleResource> | undefined {
|
|
85
|
-
return this.lastConversionResponse;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
clearStoredResponses(): void {
|
|
89
|
-
this.lastTenantConfigResponse = undefined;
|
|
90
|
-
this.lastConversionResponse = undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
getTenantConfigEntries(
|
|
94
|
-
response: DataConvDidCommResponse<TenantAdapterConfigResource> | undefined = this.lastTenantConfigResponse
|
|
95
|
-
): Array<TenantAdapterConfigEntry<TenantAdapterConfigResource>> {
|
|
96
|
-
const entries = response?.body?.data;
|
|
97
|
-
return Array.isArray(entries) ? entries : [];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
getSuccessfulTenantConfigs(
|
|
101
|
-
response: DataConvDidCommResponse<TenantAdapterConfigResource> | undefined = this.lastTenantConfigResponse
|
|
102
|
-
): TenantAdapterConfigResource[] {
|
|
103
|
-
return this.getTenantConfigEntries(response)
|
|
104
|
-
.filter((entry) => typeof entry.response?.status === 'string' && entry.response.status.startsWith('2'))
|
|
105
|
-
.map((entry) => entry.resource)
|
|
106
|
-
.filter((resource): resource is TenantAdapterConfigResource => !!resource && typeof resource === 'object');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
getConversionEntry(
|
|
110
|
-
response: DataConvDidCommResponse<ConvertedBundleResource> | undefined = this.lastConversionResponse
|
|
111
|
-
): ConversionResultEntry | undefined {
|
|
112
|
-
const entries = response?.body?.data;
|
|
113
|
-
if (!Array.isArray(entries)) {
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
return entries.find((entry) => entry?.type === 'ConversionResult') as ConversionResultEntry | undefined;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
getConvertedBundle(
|
|
120
|
-
response: DataConvDidCommResponse<ConvertedBundleResource> | undefined = this.lastConversionResponse
|
|
121
|
-
): ConvertedBundleResource | undefined {
|
|
122
|
-
return this.getConversionEntry(response)?.resource;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getResponseIssues<TResource>(
|
|
126
|
-
response: DataConvDidCommResponse<TResource> | undefined
|
|
127
|
-
): DataConvOperationOutcome | undefined {
|
|
128
|
-
return response?.body?.issues;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async createTenantConfig(options: CreateTenantConfigOptions): Promise<DataConvCreateResult> {
|
|
132
|
-
return this.createConfig(options);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async createConfig(options: CreateTenantConfigOptions): Promise<DataConvCreateResult> {
|
|
136
|
-
if (!Array.isArray(options.entries) || options.entries.length === 0) {
|
|
137
|
-
throw new Error('entries is required and must contain at least one item');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const tenantId = resolveConfigTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
141
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
142
|
-
const sector = resolveSector(this.config, options.sector);
|
|
143
|
-
const softwareId = resolveConfigSoftwareId(options);
|
|
144
|
-
const envelope = buildEnvelope({
|
|
145
|
-
iss: options.iss,
|
|
146
|
-
thid: options.thid,
|
|
147
|
-
type: options.type,
|
|
148
|
-
iat: options.iat,
|
|
149
|
-
exp: options.exp,
|
|
150
|
-
idToken: options.idToken,
|
|
151
|
-
vpToken: options.vpToken,
|
|
152
|
-
data: options.entries
|
|
153
|
-
}, this.messageDeps());
|
|
154
|
-
|
|
155
|
-
const response = await this.request({
|
|
156
|
-
method: 'POST',
|
|
157
|
-
url: `/host/cds-${jurisdiction}/v1/${sector}/${tenantId}/${softwareId}/config/_create`,
|
|
158
|
-
headers: { 'Content-Type': 'application/didcomm-plain+json' },
|
|
159
|
-
body: envelope
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
if (response.status !== 202) {
|
|
163
|
-
throw new Error(`Unexpected createTenantConfig response status: ${response.status}`);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
thid: envelope.thid,
|
|
168
|
-
location: headerValue(response.headers, 'location')
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async pollTenantConfigResponse(
|
|
173
|
-
options: DataConvTenantConfigPollOptions
|
|
174
|
-
): Promise<DataConvDidCommResponse<TenantAdapterConfigResource>> {
|
|
175
|
-
return this.pollConfig(options);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async pollConfig(
|
|
179
|
-
options: DataConvTenantConfigPollOptions
|
|
180
|
-
): Promise<DataConvDidCommResponse<TenantAdapterConfigResource>> {
|
|
181
|
-
const tenantId = resolveConfigTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
182
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
183
|
-
const sector = resolveSector(this.config, options.sector);
|
|
184
|
-
const softwareId = requireText(options.softwareId, 'softwareId');
|
|
185
|
-
const thid = requireText(options.thid, 'thid');
|
|
186
|
-
|
|
187
|
-
const response = await this.pollUntilComplete<DataConvDidCommResponse<TenantAdapterConfigResource>>(
|
|
188
|
-
async () => this.request({
|
|
189
|
-
method: 'POST',
|
|
190
|
-
url: `/host/cds-${jurisdiction}/v1/${sector}/${tenantId}/${softwareId}/config/_create-response?thid=${encodeURIComponent(thid)}`,
|
|
191
|
-
headers: { 'Content-Type': 'application/didcomm-plain+json' },
|
|
192
|
-
body: buildEnvelope({
|
|
193
|
-
iss: options.iss,
|
|
194
|
-
thid,
|
|
195
|
-
type: options.type,
|
|
196
|
-
iat: options.iat,
|
|
197
|
-
exp: options.exp,
|
|
198
|
-
idToken: options.idToken,
|
|
199
|
-
vpToken: options.vpToken
|
|
200
|
-
}, this.messageDeps())
|
|
201
|
-
}),
|
|
202
|
-
`Failed polling tenant config response after ${this.retryTimes} attempts`
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
this.lastTenantConfigResponse = response;
|
|
206
|
-
return response;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
async createTenantConfigAndWait(
|
|
210
|
-
options: CreateTenantConfigOptions
|
|
211
|
-
): Promise<DataConvDidCommResponse<TenantAdapterConfigResource>> {
|
|
212
|
-
const { thid } = await this.createConfig(options);
|
|
213
|
-
return this.pollConfig({
|
|
214
|
-
alternateName: options.alternateName,
|
|
215
|
-
tenantId: options.tenantId,
|
|
216
|
-
jurisdiction: options.jurisdiction,
|
|
217
|
-
sector: options.sector,
|
|
218
|
-
softwareId: resolveConfigSoftwareId(options),
|
|
219
|
-
thid,
|
|
220
|
-
iss: options.iss,
|
|
221
|
-
type: options.type,
|
|
222
|
-
idToken: options.idToken,
|
|
223
|
-
vpToken: options.vpToken
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async uploadSpreadsheet(
|
|
228
|
-
source: string | Uint8Array,
|
|
229
|
-
options: DataConvUploadDidCommOptions
|
|
230
|
-
): Promise<DataConvUploadResult> {
|
|
231
|
-
if (typeof source === 'string') {
|
|
232
|
-
return this.uploadWithLink(source, options);
|
|
233
|
-
}
|
|
234
|
-
return this.uploadWithBinary(source, options);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async uploadWithLink(
|
|
238
|
-
source: string,
|
|
239
|
-
options: DataConvUploadDidCommOptions
|
|
240
|
-
): Promise<DataConvUploadResult> {
|
|
241
|
-
return this.uploadDidComm(source, options);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async uploadWithBinary(
|
|
245
|
-
source: Uint8Array,
|
|
246
|
-
options: DataConvUploadDidCommOptions
|
|
247
|
-
): Promise<DataConvUploadResult> {
|
|
248
|
-
return this.uploadDidComm(source, options);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
private async uploadDidComm(
|
|
252
|
-
source: string | Uint8Array,
|
|
253
|
-
options: DataConvUploadDidCommOptions
|
|
254
|
-
): Promise<DataConvUploadResult> {
|
|
255
|
-
const tenantId = resolveTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
256
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
257
|
-
const sector = resolveSector(this.config, options.sector);
|
|
258
|
-
const softwareId = requireText(options.softwareId, 'softwareId');
|
|
259
|
-
const resourceType = resolveResourceType(this.config, options.resourceType);
|
|
260
|
-
const envelope = buildEnvelope({
|
|
261
|
-
iss: options.iss,
|
|
262
|
-
thid: options.thid,
|
|
263
|
-
type: options.type,
|
|
264
|
-
iat: options.iat,
|
|
265
|
-
exp: options.exp,
|
|
266
|
-
idToken: options.idToken,
|
|
267
|
-
vpToken: options.vpToken,
|
|
268
|
-
body: options.body ?? DEFAULT_UPLOAD_BODY,
|
|
269
|
-
attachments: [buildAttachment(source, options, this.cryptoApi)],
|
|
270
|
-
extra: buildUploadExtra(options, this.config)
|
|
271
|
-
}, this.messageDeps());
|
|
272
|
-
|
|
273
|
-
const response = await this.request({
|
|
274
|
-
method: 'POST',
|
|
275
|
-
url: `/${tenantId}/cds-${jurisdiction}/v1/${sector}/digitaltwin/${softwareId}/${resourceType}/_upload`,
|
|
276
|
-
headers: { 'Content-Type': 'application/didcomm-plain+json' },
|
|
277
|
-
body: envelope
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
if (response.status !== 202) {
|
|
281
|
-
throw new Error(`Unexpected uploadSpreadsheet response status: ${response.status}`);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
thid: envelope.thid,
|
|
286
|
-
location: headerValue(response.headers, 'location')
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
async uploadSpreadsheetMultipart(options: DataConvMultipartUploadOptions): Promise<DataConvUploadResult> {
|
|
291
|
-
return this.uploadWithFile(options);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async uploadWithFile(options: DataConvMultipartUploadOptions): Promise<DataConvUploadResult> {
|
|
295
|
-
const tenantId = resolveTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
296
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
297
|
-
const sector = resolveSector(this.config, options.sector);
|
|
298
|
-
const softwareId = requireText(options.softwareId, 'softwareId');
|
|
299
|
-
const resourceType = resolveResourceType(this.config, options.resourceType);
|
|
300
|
-
const sourceFormat = normalizeSourceFormat(options.sourceFormat, this.config);
|
|
301
|
-
const envelope = buildEnvelope({
|
|
302
|
-
iss: options.iss,
|
|
303
|
-
thid: options.thid,
|
|
304
|
-
type: options.type,
|
|
305
|
-
iat: options.iat,
|
|
306
|
-
exp: options.exp,
|
|
307
|
-
idToken: options.idToken,
|
|
308
|
-
vpToken: options.vpToken,
|
|
309
|
-
extra: buildUploadExtra(options, this.config)
|
|
310
|
-
}, this.messageDeps());
|
|
311
|
-
|
|
312
|
-
const formData = buildMultipartFormData(
|
|
313
|
-
options.fileBytes,
|
|
314
|
-
options.fileName || (sourceFormat === 'csv' ? 'input.csv' : 'input.xlsx'),
|
|
315
|
-
options.mediaType || (sourceFormat === 'csv' ? 'text/csv' : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'),
|
|
316
|
-
envelope
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
const response = await this.request({
|
|
320
|
-
method: 'POST',
|
|
321
|
-
url: `/${tenantId}/cds-${jurisdiction}/v1/${sector}/digitaltwin/${softwareId}/${resourceType}/_upload`,
|
|
322
|
-
body: formData
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
if (response.status !== 202) {
|
|
326
|
-
throw new Error(`Unexpected uploadSpreadsheetMultipart response status: ${response.status}`);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return {
|
|
330
|
-
thid: envelope.thid,
|
|
331
|
-
location: headerValue(response.headers, 'location')
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
async pollConversionResponse(
|
|
336
|
-
options: DataConvConversionPollOptions
|
|
337
|
-
): Promise<DataConvDidCommResponse<ConvertedBundleResource>> {
|
|
338
|
-
return this.pollUploadResponse(options);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
async pollUploadResponse(
|
|
342
|
-
options: DataConvConversionPollOptions
|
|
343
|
-
): Promise<DataConvDidCommResponse<ConvertedBundleResource>> {
|
|
344
|
-
const tenantId = resolveTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
345
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
346
|
-
const sector = resolveSector(this.config, options.sector);
|
|
347
|
-
const softwareId = requireText(options.softwareId, 'softwareId');
|
|
348
|
-
const resourceType = resolveResourceType(this.config, options.resourceType);
|
|
349
|
-
const thid = requireText(options.thid, 'thid');
|
|
350
|
-
|
|
351
|
-
const response = await this.pollUntilComplete<DataConvDidCommResponse<ConvertedBundleResource>>(
|
|
352
|
-
async () => this.request({
|
|
353
|
-
method: 'POST',
|
|
354
|
-
url: `/${tenantId}/cds-${jurisdiction}/v1/${sector}/digitaltwin/${softwareId}/${resourceType}/_upload-response?thid=${encodeURIComponent(thid)}`,
|
|
355
|
-
headers: { 'Content-Type': 'application/didcomm-plain+json' },
|
|
356
|
-
body: buildEnvelope({
|
|
357
|
-
iss: options.iss,
|
|
358
|
-
thid,
|
|
359
|
-
type: options.type,
|
|
360
|
-
iat: options.iat,
|
|
361
|
-
exp: options.exp,
|
|
362
|
-
idToken: options.idToken,
|
|
363
|
-
vpToken: options.vpToken
|
|
364
|
-
}, this.messageDeps())
|
|
365
|
-
}),
|
|
366
|
-
`Failed polling conversion response after ${this.retryTimes} attempts`
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
this.lastConversionResponse = response;
|
|
370
|
-
return response;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
async uploadSpreadsheetAndWait(
|
|
374
|
-
source: string | Uint8Array,
|
|
375
|
-
options: DataConvUploadDidCommOptions
|
|
376
|
-
): Promise<DataConvDidCommResponse<ConvertedBundleResource>> {
|
|
377
|
-
const { thid } = await this.uploadSpreadsheet(source, options);
|
|
378
|
-
return this.pollUploadResponse({
|
|
379
|
-
alternateName: options.alternateName,
|
|
380
|
-
tenantId: options.tenantId,
|
|
381
|
-
jurisdiction: options.jurisdiction,
|
|
382
|
-
sector: options.sector,
|
|
383
|
-
softwareId: options.softwareId,
|
|
384
|
-
resourceType: options.resourceType,
|
|
385
|
-
thid,
|
|
386
|
-
iss: options.iss,
|
|
387
|
-
type: options.type,
|
|
388
|
-
idToken: options.idToken,
|
|
389
|
-
vpToken: options.vpToken
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
async patchConversion(options: DataConvPatchOptions): Promise<DataConvPatchResponse> {
|
|
394
|
-
const tenantId = resolveTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
395
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
396
|
-
const sector = resolveSector(this.config, options.sector);
|
|
397
|
-
const softwareId = requireText(options.softwareId, 'softwareId');
|
|
398
|
-
const resourceType = requireText(options.resourceType || 'Composition', 'resourceType');
|
|
399
|
-
const thid = requireText(options.thid, 'thid');
|
|
400
|
-
|
|
401
|
-
const response = await this.request({
|
|
402
|
-
method: 'POST',
|
|
403
|
-
url: `/${tenantId}/cds-${jurisdiction}/v1/${sector}/digitaltwin/${softwareId}/${resourceType}/_patch?thid=${encodeURIComponent(thid)}`,
|
|
404
|
-
headers: { 'Content-Type': 'application/didcomm-plain+json' },
|
|
405
|
-
body: buildEnvelope({
|
|
406
|
-
iss: options.iss,
|
|
407
|
-
thid,
|
|
408
|
-
type: options.type,
|
|
409
|
-
iat: options.iat,
|
|
410
|
-
exp: options.exp,
|
|
411
|
-
idToken: options.idToken,
|
|
412
|
-
vpToken: options.vpToken
|
|
413
|
-
}, this.messageDeps())
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
if (response.status !== 200) {
|
|
417
|
-
throw new Error(`Unexpected patchConversion response status: ${response.status}`);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return response.data as DataConvPatchResponse;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
async batchPromotion(options: DataConvBatchOptions): Promise<DataConvPatchResponse> {
|
|
424
|
-
const tenantId = resolveTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
425
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
426
|
-
const sector = resolveSector(this.config, options.sector);
|
|
427
|
-
const softwareId = requireText(options.softwareId, 'softwareId');
|
|
428
|
-
const resourceType = requireText(options.resourceType || 'Patient', 'resourceType');
|
|
429
|
-
const thid = requireText(options.thid, 'thid');
|
|
430
|
-
|
|
431
|
-
const response = await this.request({
|
|
432
|
-
method: 'POST',
|
|
433
|
-
url: `/${tenantId}/cds-${jurisdiction}/v1/${sector}/digitaltwin/${softwareId}/${resourceType}/_batch?thid=${encodeURIComponent(thid)}`,
|
|
434
|
-
headers: { 'Content-Type': 'application/didcomm-plain+json' },
|
|
435
|
-
body: buildEnvelope({
|
|
436
|
-
iss: options.iss,
|
|
437
|
-
thid,
|
|
438
|
-
type: options.type,
|
|
439
|
-
iat: options.iat,
|
|
440
|
-
exp: options.exp,
|
|
441
|
-
idToken: options.idToken,
|
|
442
|
-
vpToken: options.vpToken
|
|
443
|
-
}, this.messageDeps())
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
if (response.status !== 200) {
|
|
447
|
-
throw new Error(`Unexpected batchPromotion response status: ${response.status}`);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return response.data as DataConvPatchResponse;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
async searchResources<TResource = Record<string, unknown>>(
|
|
454
|
-
options: DataConvSearchOptions
|
|
455
|
-
): Promise<DataConvSearchBundle<TResource>> {
|
|
456
|
-
const tenantId = resolveTenantId(this.config, options.tenantId ?? options.alternateName);
|
|
457
|
-
const jurisdiction = resolveJurisdiction(this.config, options.jurisdiction);
|
|
458
|
-
const sector = resolveSector(this.config, options.sector);
|
|
459
|
-
const resourceType = requireText(options.resourceType, 'resourceType');
|
|
460
|
-
const searchParams = normalizeSearchParams(
|
|
461
|
-
options.searchParams && typeof options.searchParams === 'object'
|
|
462
|
-
? options.searchParams as Record<string, unknown>
|
|
463
|
-
: undefined
|
|
464
|
-
);
|
|
465
|
-
const authToken = String(options.authorizationToken || options.idToken || this.idToken || '').trim();
|
|
466
|
-
const headers: Record<string, string> = {
|
|
467
|
-
'Content-Type': 'application/json'
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
if (authToken) {
|
|
471
|
-
headers.Authorization = `Bearer ${authToken}`;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const response = await this.request({
|
|
475
|
-
method: 'POST',
|
|
476
|
-
url: `/host/cds-${jurisdiction}/v1/${sector}/${tenantId}/org.hl7.fhir.api/${resourceType}/_search`,
|
|
477
|
-
headers,
|
|
478
|
-
body: searchParams
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
if (response.status !== 200) {
|
|
482
|
-
throw new Error(`Unexpected searchResources response status: ${response.status}`);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
return response.data as DataConvSearchBundle<TResource>;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
private async pollUntilComplete<T>(
|
|
489
|
-
requestFactory: () => Promise<{ status: number; headers: Record<string, string>; data: unknown }>,
|
|
490
|
-
errorMessage: string
|
|
491
|
-
): Promise<T> {
|
|
492
|
-
for (let attempt = 0; attempt < this.retryTimes; attempt += 1) {
|
|
493
|
-
const response = await requestFactory();
|
|
494
|
-
if (response.status === 200) {
|
|
495
|
-
return response.data as T;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
const retryAfter = headerValue(response.headers, 'retry-after');
|
|
499
|
-
const retrySeconds = retryAfter ? Number(retryAfter) : undefined;
|
|
500
|
-
const delayMs = retrySeconds !== undefined && !Number.isNaN(retrySeconds)
|
|
501
|
-
? retrySeconds * 1000
|
|
502
|
-
: this.retryDelayMs;
|
|
503
|
-
await sleep(delayMs);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
throw new Error(errorMessage);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
private async request(options: {
|
|
510
|
-
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
511
|
-
url: string;
|
|
512
|
-
headers?: Record<string, string>;
|
|
513
|
-
body?: unknown;
|
|
514
|
-
}): Promise<{ status: number; headers: Record<string, string>; data: unknown }> {
|
|
515
|
-
const headers = options.headers ?? {};
|
|
516
|
-
|
|
517
|
-
if (this.httpClient) {
|
|
518
|
-
const response = await this.httpClient.request({
|
|
519
|
-
method: options.method,
|
|
520
|
-
url: options.url,
|
|
521
|
-
data: options.body,
|
|
522
|
-
headers,
|
|
523
|
-
validateStatus: () => true
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
return {
|
|
527
|
-
status: response.status,
|
|
528
|
-
headers: (response.headers || {}) as Record<string, string>,
|
|
529
|
-
data: response.data
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
if (!this.fetchFn) {
|
|
534
|
-
throw new Error('No HTTP transport available: provide axios httpClient or fetch implementation');
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const response = await this.fetchFn(buildUrl(this.baseUrl, options.url), {
|
|
538
|
-
method: options.method,
|
|
539
|
-
headers,
|
|
540
|
-
body: options.body === undefined
|
|
541
|
-
? undefined
|
|
542
|
-
: isFormData(options.body)
|
|
543
|
-
? options.body
|
|
544
|
-
: typeof options.body === 'string'
|
|
545
|
-
? options.body
|
|
546
|
-
: JSON.stringify(options.body)
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
const contentType = response.headers.get('content-type') || '';
|
|
550
|
-
const data = contentType.includes('json') ? await response.json() : await response.text();
|
|
551
|
-
return {
|
|
552
|
-
status: response.status,
|
|
553
|
-
headers: headersToObject(response.headers),
|
|
554
|
-
data
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
private messageDeps() {
|
|
559
|
-
return {
|
|
560
|
-
config: this.config,
|
|
561
|
-
cryptoApi: this.cryptoApi,
|
|
562
|
-
defaultExpSeconds: this.defaultExpSeconds,
|
|
563
|
-
currentIdToken: this.idToken,
|
|
564
|
-
currentVpToken: this.vpToken
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
}
|