gdc-sdk-node-ts 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 +166 -0
- package/dist/async-polling.d.ts +7 -0
- package/dist/async-polling.js +26 -0
- package/dist/device-activation.d.ts +44 -0
- package/dist/device-activation.js +44 -0
- package/dist/gdc-session-bridge.d.ts +11 -0
- package/dist/gdc-session-bridge.js +74 -0
- package/dist/host-onboarding.d.ts +38 -0
- package/dist/host-onboarding.js +39 -0
- package/dist/identity-bootstrap.d.ts +30 -0
- package/dist/identity-bootstrap.js +32 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +24 -0
- package/dist/individual-onboarding.d.ts +35 -0
- package/dist/individual-onboarding.js +38 -0
- package/dist/individual-start.d.ts +87 -0
- package/dist/individual-start.js +82 -0
- package/dist/legacy-compat.d.ts +22 -0
- package/dist/legacy-compat.js +18 -0
- package/dist/node-runtime-client.d.ts +195 -0
- package/dist/node-runtime-client.js +483 -0
- package/dist/orchestration/client-port.d.ts +47 -0
- package/dist/orchestration/client-port.js +31 -0
- package/dist/orchestration/host-onboarding-sdk.d.ts +14 -0
- package/dist/orchestration/host-onboarding-sdk.js +15 -0
- package/dist/orchestration/individual-controller-sdk.d.ts +54 -0
- package/dist/orchestration/individual-controller-sdk.js +70 -0
- package/dist/orchestration/individual-member-sdk.d.ts +17 -0
- package/dist/orchestration/individual-member-sdk.js +20 -0
- package/dist/orchestration/organization-controller-sdk.d.ts +46 -0
- package/dist/orchestration/organization-controller-sdk.js +56 -0
- package/dist/orchestration/organization-employee-sdk.d.ts +9 -0
- package/dist/orchestration/organization-employee-sdk.js +13 -0
- package/dist/orchestration/personal-sdk.d.ts +22 -0
- package/dist/orchestration/personal-sdk.js +34 -0
- package/dist/orchestration/professional-sdk.d.ts +58 -0
- package/dist/orchestration/professional-sdk.js +63 -0
- package/dist/poll-options.d.ts +1 -0
- package/dist/poll-options.js +2 -0
- package/dist/resource-operations.d.ts +225 -0
- package/dist/resource-operations.js +184 -0
- package/dist/runtime-contracts.d.ts +65 -0
- package/dist/runtime-contracts.js +7 -0
- package/dist/session.d.ts +64 -0
- package/dist/session.js +80 -0
- package/dist/simple-device-activation.d.ts +44 -0
- package/dist/simple-device-activation.js +44 -0
- package/dist/simple-host-onboarding.d.ts +27 -0
- package/dist/simple-host-onboarding.js +39 -0
- package/dist/simple-individual-onboarding.d.ts +27 -0
- package/dist/simple-individual-onboarding.js +38 -0
- package/dist/simple-individual-start.d.ts +45 -0
- package/dist/simple-individual-start.js +59 -0
- package/dist/simple-poll-options.d.ts +5 -0
- package/dist/simple-poll-options.js +17 -0
- package/dist/simple-smart-token.d.ts +58 -0
- package/dist/simple-smart-token.js +85 -0
- package/dist/smart-token.d.ts +135 -0
- package/dist/smart-token.js +100 -0
- package/package.json +26 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { buildConsentClaimsSimpleWithCid } from 'gdc-common-utils-ts/utils/consent';
|
|
5
|
+
import { pollUntilCompleteWithMethod } from './async-polling.js';
|
|
6
|
+
import { confirmLegalOrganizationOrderWithDeps } from './host-onboarding.js';
|
|
7
|
+
import { confirmIndividualOrganizationOrderWithDeps, } from './individual-onboarding.js';
|
|
8
|
+
import { requestSmartTokenWithDeps } from './smart-token.js';
|
|
9
|
+
import { startIndividualOrganizationWithDeps } from './individual-start.js';
|
|
10
|
+
import { createOrganizationEmployeeWithDeps, grantProfessionalAccessWithDeps, ingestCommunicationAndUpdateIndexWithDeps, searchClinicalBundleWithDeps, searchLatestIpsWithDeps, upsertRelatedPersonAndPollWithDeps, } from './resource-operations.js';
|
|
11
|
+
import { submitAndPollWithMethods } from './orchestration/client-port.js';
|
|
12
|
+
/**
|
|
13
|
+
* Runtime-oriented HTTP client for Node backends, BFFs, and workers that need
|
|
14
|
+
* to submit GDC gateway requests and poll asynchronous responses.
|
|
15
|
+
*
|
|
16
|
+
* This class is intentionally transport-focused. It does not try to be the
|
|
17
|
+
* high-level editor of FHIR documents; that role belongs to the shared helpers
|
|
18
|
+
* re-exported from `gdc-sdk-core-ts`.
|
|
19
|
+
*/
|
|
20
|
+
export class HttpRuntimeClient {
|
|
21
|
+
/**
|
|
22
|
+
* @param options.baseUrl Gateway base URL without trailing slash.
|
|
23
|
+
* @param options.interopMode Optional runtime interoperability mode from the SDK config layer (`demo`, `compat`, `strict`).
|
|
24
|
+
* @param options.bearerToken Optional bearer token reused for direct HTTP calls.
|
|
25
|
+
* @param options.ctx Optional default route context.
|
|
26
|
+
* @param options.defaultHeaders Optional static headers appended to every request.
|
|
27
|
+
* @param options.requestTimeoutMs Optional per-request timeout in milliseconds.
|
|
28
|
+
*/
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.tokenCache = new Map();
|
|
31
|
+
this.baseUrl = String(options.baseUrl || '').replace(/\/+$/, '');
|
|
32
|
+
this.bearerToken = String(options.bearerToken || '').trim() || undefined;
|
|
33
|
+
this.ctx = options.ctx;
|
|
34
|
+
this.defaultHeaders = options.defaultHeaders || {};
|
|
35
|
+
this.requestTimeoutMs = Math.max(1, Math.floor(options.requestTimeoutMs ?? 15000));
|
|
36
|
+
this.httpTraceFile = String(process.env.SDK_HTTP_TRACE_FILE || '').trim() || undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Builds a canonical GDC v1 resource/action path from a route context.
|
|
40
|
+
*/
|
|
41
|
+
v1Path(ctx, section, format, resourceType, action) {
|
|
42
|
+
const routeCtx = this.requireRouteContext(ctx);
|
|
43
|
+
return `/${encodeURIComponent(routeCtx.tenantId)}/cds-${encodeURIComponent(routeCtx.jurisdiction)}/v1/${encodeURIComponent(routeCtx.sector)}/${encodeURIComponent(section)}/${encodeURIComponent(format)}/${encodeURIComponent(resourceType)}/${encodeURIComponent(action)}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Submits a batch payload to a gateway batch endpoint.
|
|
47
|
+
*/
|
|
48
|
+
async submitBatch(path, payload) {
|
|
49
|
+
return this.postJson(path, payload, 'application/didcomm-plaintext+json');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Polls a batch-response endpoint until the GW reports a terminal state.
|
|
53
|
+
*/
|
|
54
|
+
async pollUntilComplete(pollPath, request, pollOptions) {
|
|
55
|
+
return pollUntilCompleteWithMethod(this.pollBatchResponse.bind(this), pollPath, request, pollOptions);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convenience wrapper that performs submit and poll in sequence.
|
|
59
|
+
*/
|
|
60
|
+
async submitAndPoll(submitPath, pollPath, payload, pollOptions) {
|
|
61
|
+
return submitAndPollWithMethods(this, submitPath, pollPath, payload, pollOptions);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Activates a legal organization in the gateway host registry using an ICA
|
|
65
|
+
* proof token already obtained by the caller.
|
|
66
|
+
*/
|
|
67
|
+
async activateOrganizationInGatewayFromIcaProof(hostCtx, input, pollOptions) {
|
|
68
|
+
const thid = `activate-org-${runtimeUuid()}`;
|
|
69
|
+
const payload = {
|
|
70
|
+
thid,
|
|
71
|
+
iss: String(hostCtx.controllerDid || '').trim() || undefined,
|
|
72
|
+
aud: String(hostCtx.hostDid || '').trim() || undefined,
|
|
73
|
+
type: 'application/api+json',
|
|
74
|
+
body: {
|
|
75
|
+
vp_token: input.vpToken,
|
|
76
|
+
...(input.controller ? { controller: input.controller } : {}),
|
|
77
|
+
data: [{
|
|
78
|
+
type: 'Organization-activation-request-v1.0',
|
|
79
|
+
meta: {
|
|
80
|
+
claims: {
|
|
81
|
+
'@context': 'org.schema',
|
|
82
|
+
...(input.additionalClaims || {}),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
resource: {
|
|
86
|
+
meta: {
|
|
87
|
+
claims: {
|
|
88
|
+
'@context': 'org.schema',
|
|
89
|
+
...(input.additionalClaims || {}),
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
}],
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
return this.submitAndPoll(this.hostRegistryOrganizationActivatePath(hostCtx), this.hostRegistryOrganizationActivatePollPath(hostCtx), payload, pollOptions);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Confirms a host-side legal organization order after the initial activation.
|
|
100
|
+
*/
|
|
101
|
+
async confirmLegalOrganizationOrder(hostCtx, input, pollOptions) {
|
|
102
|
+
return confirmLegalOrganizationOrderWithDeps({
|
|
103
|
+
input,
|
|
104
|
+
hostCtx,
|
|
105
|
+
hostRegistryOrderBatchPath: this.hostRegistryOrderBatchPath.bind(this),
|
|
106
|
+
hostRegistryOrderPollPath: this.hostRegistryOrderPollPath.bind(this),
|
|
107
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
108
|
+
defaultTimeoutMs: pollOptions?.timeoutMs,
|
|
109
|
+
defaultIntervalMs: pollOptions?.intervalMs,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Creates an employee or professional entry under an existing organization tenant.
|
|
114
|
+
*/
|
|
115
|
+
async createOrganizationEmployee(ctx, input, pollOptions) {
|
|
116
|
+
return createOrganizationEmployeeWithDeps(ctx, input, pollOptions, {
|
|
117
|
+
employeeBatchPath: this.employeeBatchPath.bind(this),
|
|
118
|
+
employeePollPath: this.employeePollPath.bind(this),
|
|
119
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Starts the onboarding flow for an individual-oriented tenant or index.
|
|
124
|
+
*/
|
|
125
|
+
async startIndividualOrganization(input) {
|
|
126
|
+
const routeCtx = this.routeCtxFromInput(input);
|
|
127
|
+
return startIndividualOrganizationWithDeps({
|
|
128
|
+
input,
|
|
129
|
+
routeCtx,
|
|
130
|
+
individualFamilyOrganizationBatchPath: this.individualFamilyOrganizationBatchPath.bind(this),
|
|
131
|
+
individualFamilyOrganizationPollPath: this.individualFamilyOrganizationPollPath.bind(this),
|
|
132
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
133
|
+
getOfferIdFromResponse: (result) => this.extractOfferId(result.poll.body),
|
|
134
|
+
getOfferPreviewFromResponse: () => ({}),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Confirms the order returned by `startIndividualOrganization(...)`.
|
|
139
|
+
*/
|
|
140
|
+
async confirmIndividualOrganizationOrder(input) {
|
|
141
|
+
const routeCtx = this.routeCtxFromInput(input);
|
|
142
|
+
return confirmIndividualOrganizationOrderWithDeps({
|
|
143
|
+
input,
|
|
144
|
+
routeCtx,
|
|
145
|
+
individualFamilyOrderBatchPath: this.individualFamilyOrderBatchPath.bind(this),
|
|
146
|
+
individualFamilyOrderPollPath: this.individualFamilyOrderPollPath.bind(this),
|
|
147
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Creates and submits a consent-oriented access grant for a professional actor.
|
|
152
|
+
*/
|
|
153
|
+
async grantProfessionalAccess(ctx, input) {
|
|
154
|
+
return grantProfessionalAccessWithDeps(ctx, input, {
|
|
155
|
+
buildConsentClaimsWithCid: this.buildConsentClaimsWithCid.bind(this),
|
|
156
|
+
individualConsentR4BatchPath: this.individualConsentR4BatchPath.bind(this),
|
|
157
|
+
individualConsentR4PollPath: this.individualConsentR4PollPath.bind(this),
|
|
158
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Requests SMART/OpenID token material through the gateway.
|
|
163
|
+
*
|
|
164
|
+
* The business inputs are typically the actor DID plus requested scopes.
|
|
165
|
+
* Route details are resolved either from `input` compatibility fields
|
|
166
|
+
* (`tenantId` / `jurisdiction` / `sector`) or from
|
|
167
|
+
* the default client route context configured in the constructor.
|
|
168
|
+
*/
|
|
169
|
+
async requestSmartToken(input) {
|
|
170
|
+
const routeCtx = this.routeCtxFromInput(input);
|
|
171
|
+
return requestSmartTokenWithDeps({
|
|
172
|
+
input,
|
|
173
|
+
routeCtx,
|
|
174
|
+
baseUrl: this.baseUrl,
|
|
175
|
+
defaultTimeoutMs: undefined,
|
|
176
|
+
defaultIntervalMs: undefined,
|
|
177
|
+
identityTokenExchangePath: this.identityTokenExchangePath.bind(this),
|
|
178
|
+
identityTokenExchangePollPath: this.identityTokenExchangePollPath.bind(this),
|
|
179
|
+
identityOpenIdSmartTokenPath: this.identityOpenIdSmartTokenPath.bind(this),
|
|
180
|
+
identityOpenIdSmartTokenPollPath: this.identityOpenIdSmartTokenPollPath.bind(this),
|
|
181
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
182
|
+
setTokenCache: (tokenCacheKey, token) => this.tokenCache.set(tokenCacheKey, token),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Creates or updates a `RelatedPerson` for non-employee family/caregiver
|
|
187
|
+
* roles such as a grandfather, guardian, or external caregiver.
|
|
188
|
+
*/
|
|
189
|
+
async upsertRelatedPersonAndPoll(ctx, input) {
|
|
190
|
+
return upsertRelatedPersonAndPollWithDeps(ctx, input, {
|
|
191
|
+
individualRelatedPersonBatchPath: this.individualRelatedPersonBatchPath.bind(this),
|
|
192
|
+
individualRelatedPersonPollPath: this.individualRelatedPersonPollPath.bind(this),
|
|
193
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Submits a FHIR `Communication` ingestion request and polls until the
|
|
198
|
+
* GW has persisted the audit record and related projections.
|
|
199
|
+
*
|
|
200
|
+
* @param ctx Route context containing tenant/jurisdiction/sector.
|
|
201
|
+
* @param input Communication payload plus route/format options.
|
|
202
|
+
*/
|
|
203
|
+
async ingestCommunicationAndUpdateIndex(ctx, input) {
|
|
204
|
+
return ingestCommunicationAndUpdateIndexWithDeps(ctx, input, {
|
|
205
|
+
individualCommunicationBatchPath: this.individualCommunicationBatchPath.bind(this),
|
|
206
|
+
individualCommunicationPollPath: this.individualCommunicationPollPath.bind(this),
|
|
207
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Alias for `ingestCommunicationAndUpdateIndex(...)`.
|
|
212
|
+
*
|
|
213
|
+
* @param ctx Route context containing tenant/jurisdiction/sector.
|
|
214
|
+
* @param input Communication payload plus route/format options.
|
|
215
|
+
*/
|
|
216
|
+
async submitCommunicationAndPoll(ctx, input) {
|
|
217
|
+
return this.ingestCommunicationAndUpdateIndex(ctx, input);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Executes a clinical `Bundle/_search` through the converged runtime.
|
|
221
|
+
*
|
|
222
|
+
* @param ctx Route context containing tenant/jurisdiction/sector.
|
|
223
|
+
* @param input Search parameters such as subject, section, date and included resource types.
|
|
224
|
+
*/
|
|
225
|
+
async searchClinicalBundle(ctx, input) {
|
|
226
|
+
return searchClinicalBundleWithDeps(ctx, input, {
|
|
227
|
+
bundleSearchPath: this.individualBundleSearchPath.bind(this),
|
|
228
|
+
bundleSearchPollPath: this.individualBundleSearchPollPath.bind(this),
|
|
229
|
+
submitAndPoll: this.submitAndPoll.bind(this),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Searches the latest IPS-oriented document view for a subject.
|
|
234
|
+
*
|
|
235
|
+
* Defaults the section to the IPS patient summary document and includes
|
|
236
|
+
* `Composition` plus `DocumentReference`.
|
|
237
|
+
*
|
|
238
|
+
* @param ctx Route context containing tenant/jurisdiction/sector.
|
|
239
|
+
* @param input Subject-scoped search parameters.
|
|
240
|
+
*/
|
|
241
|
+
async searchLatestIps(ctx, input) {
|
|
242
|
+
return searchLatestIpsWithDeps(ctx, input, {
|
|
243
|
+
searchClinicalBundle: this.searchClinicalBundle.bind(this),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Searches a communication/document thread using `thid` and returns the
|
|
248
|
+
* indexed communication/document projections.
|
|
249
|
+
*/
|
|
250
|
+
async listCommunicationThread(ctx, input) {
|
|
251
|
+
return this.searchClinicalBundle(ctx, {
|
|
252
|
+
subject: input.subject,
|
|
253
|
+
thid: input.thid,
|
|
254
|
+
includedTypes: ['Communication', 'DocumentReference', 'Composition'],
|
|
255
|
+
pollOptions: input.pollOptions,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
buildConsentClaimsWithCid(input) {
|
|
259
|
+
return buildConsentClaimsSimpleWithCid({
|
|
260
|
+
subjectDid: input.subjectDid,
|
|
261
|
+
subjectPhone: input.subjectPhone,
|
|
262
|
+
subjectGivenName: input.subjectGivenName,
|
|
263
|
+
actor: input.actorId ?? input.actor ?? '',
|
|
264
|
+
actorRole: String(input?.actorRole || ''),
|
|
265
|
+
purpose: String(input?.purpose || ''),
|
|
266
|
+
actions: Array.isArray(input?.actions) ? input.actions : [],
|
|
267
|
+
consentIdentifier: input.consentIdentifier,
|
|
268
|
+
consentDate: input.consentDate,
|
|
269
|
+
decision: input.decision,
|
|
270
|
+
attachmentContentType: input.attachmentContentType,
|
|
271
|
+
attachmentBase64: input.attachmentBase64,
|
|
272
|
+
}, {
|
|
273
|
+
errorPrefix: 'grantProfessionalAccess:',
|
|
274
|
+
consentIdentifierFactory: () => `urn:uuid:${runtimeUuid()}`,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
async pollBatchResponse(path, request) {
|
|
278
|
+
const response = await this.fetchWithTimeout(path, {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
headers: this.buildHeaders('application/json'),
|
|
281
|
+
body: JSON.stringify(request),
|
|
282
|
+
});
|
|
283
|
+
const retryAfter = Number(response.headers.get('retry-after'));
|
|
284
|
+
return {
|
|
285
|
+
status: response.status,
|
|
286
|
+
body: await this.parseResponseBody(response),
|
|
287
|
+
retryAfterMs: Number.isFinite(retryAfter) ? retryAfter * 1000 : undefined,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
async postJson(path, payload, contentType) {
|
|
291
|
+
const response = await this.fetchWithTimeout(path, {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
headers: this.buildHeaders(contentType),
|
|
294
|
+
body: JSON.stringify(payload),
|
|
295
|
+
});
|
|
296
|
+
return { status: response.status, location: response.headers.get('location') || undefined, body: await this.parseResponseBody(response) };
|
|
297
|
+
}
|
|
298
|
+
buildHeaders(contentType) {
|
|
299
|
+
const headers = {
|
|
300
|
+
...this.defaultHeaders,
|
|
301
|
+
'Content-Type': contentType,
|
|
302
|
+
Accept: 'application/json, application/didcomm-plaintext+json, */*',
|
|
303
|
+
};
|
|
304
|
+
if (this.bearerToken)
|
|
305
|
+
headers.Authorization = `Bearer ${this.bearerToken}`;
|
|
306
|
+
return headers;
|
|
307
|
+
}
|
|
308
|
+
async fetchWithTimeout(path, init) {
|
|
309
|
+
const controller = new AbortController();
|
|
310
|
+
const timeout = setTimeout(() => controller.abort(), this.requestTimeoutMs);
|
|
311
|
+
const url = /^https?:\/\//.test(path) ? path : `${this.baseUrl}${path.startsWith('/') ? path : `/${path}`}`;
|
|
312
|
+
const requestBody = this.parseTraceBody(init.body);
|
|
313
|
+
const traceBase = {
|
|
314
|
+
ts: new Date().toISOString(),
|
|
315
|
+
request: {
|
|
316
|
+
url,
|
|
317
|
+
method: String(init.method || 'GET').toUpperCase(),
|
|
318
|
+
headers: this.redactTraceValue(init.headers || {}),
|
|
319
|
+
body: this.redactTraceValue(requestBody),
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
try {
|
|
323
|
+
const response = await fetch(url, { ...init, signal: controller.signal });
|
|
324
|
+
const responseClone = response.clone();
|
|
325
|
+
const responseRaw = await responseClone.text();
|
|
326
|
+
this.appendHttpTrace({
|
|
327
|
+
...traceBase,
|
|
328
|
+
response: {
|
|
329
|
+
status: response.status,
|
|
330
|
+
headers: this.redactTraceValue(Object.fromEntries(response.headers.entries())),
|
|
331
|
+
body: this.redactTraceValue(this.parseTraceRawText(responseRaw)),
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
return response;
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
this.appendHttpTrace({
|
|
338
|
+
...traceBase,
|
|
339
|
+
error: {
|
|
340
|
+
name: error instanceof Error ? error.name : 'Error',
|
|
341
|
+
message: error instanceof Error ? error.message : String(error),
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
finally {
|
|
347
|
+
clearTimeout(timeout);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async parseResponseBody(response) {
|
|
351
|
+
const raw = await response.text();
|
|
352
|
+
if (!raw)
|
|
353
|
+
return {};
|
|
354
|
+
try {
|
|
355
|
+
return JSON.parse(raw);
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
return raw;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
requireRouteContext(ctx) {
|
|
362
|
+
const resolved = ctx || this.ctx;
|
|
363
|
+
const tenantId = String(resolved?.tenantId || '').trim();
|
|
364
|
+
const jurisdiction = String(resolved?.jurisdiction || '').trim();
|
|
365
|
+
const sector = String(resolved?.sector || '').trim();
|
|
366
|
+
if (!tenantId || !jurisdiction || !sector) {
|
|
367
|
+
throw new Error('Route context is required.');
|
|
368
|
+
}
|
|
369
|
+
return { tenantId, jurisdiction, sector };
|
|
370
|
+
}
|
|
371
|
+
routeCtxFromInput(input) {
|
|
372
|
+
const tenantId = String(input.serviceProviderDid || input.tenantId || '').trim();
|
|
373
|
+
return this.requireRouteContext(tenantId && input.jurisdiction && input.sector
|
|
374
|
+
? { tenantId, jurisdiction: input.jurisdiction, sector: input.sector }
|
|
375
|
+
: undefined);
|
|
376
|
+
}
|
|
377
|
+
hostRegistryPath(ctx, resourceType, action) {
|
|
378
|
+
const hostCtx = this.requireHostRouteContext(ctx);
|
|
379
|
+
return `/host/cds-${encodeURIComponent(hostCtx.jurisdiction)}/v1/${encodeURIComponent(hostCtx.sector)}/registry/org.schema/${encodeURIComponent(resourceType)}/${encodeURIComponent(action)}`;
|
|
380
|
+
}
|
|
381
|
+
requireHostRouteContext(ctx) {
|
|
382
|
+
const jurisdiction = String(ctx?.jurisdiction || this.ctx?.jurisdiction || '').trim();
|
|
383
|
+
const sector = String(ctx?.sector || this.ctx?.sector || '').trim();
|
|
384
|
+
if (!jurisdiction || !sector)
|
|
385
|
+
throw new Error('Host route context is required.');
|
|
386
|
+
return { jurisdiction, sector };
|
|
387
|
+
}
|
|
388
|
+
hostRegistryOrganizationActivatePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', '_activate'); }
|
|
389
|
+
hostRegistryOrganizationActivatePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', '_activate-response'); }
|
|
390
|
+
hostRegistryOrderBatchPath(ctx) { return this.hostRegistryPath(ctx, 'Order', '_batch'); }
|
|
391
|
+
hostRegistryOrderPollPath(ctx) { return this.hostRegistryPath(ctx, 'Order', '_batch-response'); }
|
|
392
|
+
employeeBatchPath(ctx) { return this.v1Path(ctx, 'entity', 'org.schema', 'Employee', '_batch'); }
|
|
393
|
+
employeePollPath(ctx) { return this.v1Path(ctx, 'entity', 'org.schema', 'Employee', '_batch-response'); }
|
|
394
|
+
individualFamilyOrganizationBatchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.schema', 'Organization', '_batch'); }
|
|
395
|
+
individualFamilyOrganizationPollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.schema', 'Organization', '_batch-response'); }
|
|
396
|
+
individualFamilyOrderBatchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.schema', 'Order', '_batch'); }
|
|
397
|
+
individualFamilyOrderPollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.schema', 'Order', '_batch-response'); }
|
|
398
|
+
individualRelatedPersonBatchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'RelatedPerson', '_batch'); }
|
|
399
|
+
individualRelatedPersonPollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'RelatedPerson', '_batch-response'); }
|
|
400
|
+
individualConsentR4BatchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Consent', '_batch'); }
|
|
401
|
+
individualConsentR4PollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Consent', '_batch-response'); }
|
|
402
|
+
individualCommunicationBatchPath(ctx, format) { return this.v1Path(ctx, 'individual', format, 'Communication', '_batch'); }
|
|
403
|
+
individualCommunicationPollPath(ctx, format) { return this.v1Path(ctx, 'individual', format, 'Communication', '_batch-response'); }
|
|
404
|
+
individualBundleSearchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Bundle', '_search'); }
|
|
405
|
+
individualBundleSearchPollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Bundle', '_search-response'); }
|
|
406
|
+
identityTokenExchangePath(ctx) {
|
|
407
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_exchange`;
|
|
408
|
+
}
|
|
409
|
+
identityTokenExchangePollPath(ctx) {
|
|
410
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_exchange-response`;
|
|
411
|
+
}
|
|
412
|
+
identityOpenIdSmartTokenPath(ctx) {
|
|
413
|
+
return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/token`;
|
|
414
|
+
}
|
|
415
|
+
identityOpenIdSmartTokenPollPath(ctx) {
|
|
416
|
+
return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/_batch-response`;
|
|
417
|
+
}
|
|
418
|
+
extractOfferId(body) {
|
|
419
|
+
const root = body || {};
|
|
420
|
+
const bodyNode = root.body || root;
|
|
421
|
+
const data = bodyNode.data || [];
|
|
422
|
+
const first = data[0] || {};
|
|
423
|
+
const firstMeta = first.meta || {};
|
|
424
|
+
const resource = first.resource || {};
|
|
425
|
+
const resourceMeta = resource.meta || {};
|
|
426
|
+
const claims = firstMeta.claims
|
|
427
|
+
|| resourceMeta.claims
|
|
428
|
+
|| {};
|
|
429
|
+
return String(claims['org.schema.Offer.identifier'] || '').trim() || undefined;
|
|
430
|
+
}
|
|
431
|
+
appendHttpTrace(entry) {
|
|
432
|
+
if (!this.httpTraceFile)
|
|
433
|
+
return;
|
|
434
|
+
try {
|
|
435
|
+
fs.mkdirSync(path.dirname(this.httpTraceFile), { recursive: true });
|
|
436
|
+
fs.appendFileSync(this.httpTraceFile, `${JSON.stringify(entry)}\n`);
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// Tracing must never break runtime requests.
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
parseTraceBody(body) {
|
|
443
|
+
if (body == null)
|
|
444
|
+
return undefined;
|
|
445
|
+
if (typeof body === 'string')
|
|
446
|
+
return this.parseTraceRawText(body);
|
|
447
|
+
if (body instanceof URLSearchParams)
|
|
448
|
+
return Object.fromEntries(body.entries());
|
|
449
|
+
return '[non-text-body]';
|
|
450
|
+
}
|
|
451
|
+
parseTraceRawText(raw) {
|
|
452
|
+
if (!raw)
|
|
453
|
+
return '';
|
|
454
|
+
try {
|
|
455
|
+
return JSON.parse(raw);
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
return raw;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
redactTraceValue(value) {
|
|
462
|
+
if (value === undefined)
|
|
463
|
+
return value;
|
|
464
|
+
const serialized = JSON.stringify(value, (key, nestedValue) => {
|
|
465
|
+
if (/token|authorization|secret|password/i.test(String(key || ''))) {
|
|
466
|
+
return '[redacted]';
|
|
467
|
+
}
|
|
468
|
+
return nestedValue;
|
|
469
|
+
});
|
|
470
|
+
return serialized === undefined ? value : JSON.parse(serialized);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* @deprecated Prefer `HttpRuntimeClient`.
|
|
475
|
+
*/
|
|
476
|
+
export class NodeHttpClient extends HttpRuntimeClient {
|
|
477
|
+
}
|
|
478
|
+
function runtimeUuid() {
|
|
479
|
+
const fromCrypto = globalThis.crypto?.randomUUID?.();
|
|
480
|
+
if (fromCrypto)
|
|
481
|
+
return fromCrypto;
|
|
482
|
+
return `fallback-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
483
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ControllerBindingInput } from 'gdc-common-utils-ts/models';
|
|
2
|
+
import type { AsyncPollRequest, PollOptions, PollResult, SubmitAndPollResult, SubmitPayload, SubmitResponse } from '../../../gdc-sdk-core-ts/dist/index.js';
|
|
3
|
+
export type { AsyncPollRequest, PollOptions, PollResult, SubmitAndPollResult, SubmitPayload, SubmitResponse, } from '../../../gdc-sdk-core-ts/dist/index.js';
|
|
4
|
+
import type { EmployeeDeviceActivationResult, EmployeeDeviceActivationRequestInput } from '../device-activation.js';
|
|
5
|
+
import type { HostRouteContext, LegalOrganizationOrderInput } from '../host-onboarding.js';
|
|
6
|
+
import type { IndividualOrganizationConfirmOrderInput, RouteContext } from '../individual-onboarding.js';
|
|
7
|
+
import type { IndividualOrganizationBootstrapInput, IndividualOrganizationStartResult } from '../individual-start.js';
|
|
8
|
+
import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
|
|
9
|
+
import type { CommunicationIngestionInput, ClinicalBundleSearchInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IpsOrFhirImportInput, OrganizationEmployeeCreationInput, RelatedPersonUpsertInput } from '../resource-operations.js';
|
|
10
|
+
/**
|
|
11
|
+
* Runtime-neutral actor/application client contract as exposed by the Node SDK.
|
|
12
|
+
*
|
|
13
|
+
* New code should prefer `RuntimeClient`.
|
|
14
|
+
* `NodeRuntimeClient` is kept as a compatibility alias while package surfaces
|
|
15
|
+
* converge across runtimes.
|
|
16
|
+
*/
|
|
17
|
+
export type RuntimeClient = {
|
|
18
|
+
activateOrganizationInGatewayFromIcaProof?: (hostCtx: HostRouteContext, input: {
|
|
19
|
+
vpToken: string;
|
|
20
|
+
controller?: ControllerBindingInput;
|
|
21
|
+
additionalClaims?: Record<string, unknown>;
|
|
22
|
+
}, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
23
|
+
confirmLegalOrganizationOrder?: (hostCtx: HostRouteContext, input: LegalOrganizationOrderInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
24
|
+
createOrganizationEmployee?: (ctx: RouteContext, input: OrganizationEmployeeCreationInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
25
|
+
activateEmployeeDeviceWithActivationRequest?: (input: EmployeeDeviceActivationRequestInput) => Promise<EmployeeDeviceActivationResult>;
|
|
26
|
+
requestSmartToken?: (input: SmartTokenRequestInput) => Promise<SmartTokenExchangeResult>;
|
|
27
|
+
startIndividualOrganization?: (input: IndividualOrganizationBootstrapInput) => Promise<IndividualOrganizationStartResult>;
|
|
28
|
+
confirmIndividualOrganizationOrder?: (input: IndividualOrganizationConfirmOrderInput) => Promise<SubmitAndPollResult>;
|
|
29
|
+
ingestCommunicationAndUpdateIndex?: (ctx: RouteContext, input: CommunicationIngestionInput) => Promise<SubmitAndPollResult>;
|
|
30
|
+
grantProfessionalAccess?: (ctx: RouteContext, input: GrantProfessionalAccessInput) => Promise<GrantProfessionalAccessResult>;
|
|
31
|
+
bootstrapIndividualOrganization?: (input: IndividualOrganizationBootstrapInput) => Promise<IndividualOrganizationStartResult>;
|
|
32
|
+
importIpsOrFhirAndUpdateIndex?: (ctx: RouteContext, input: IpsOrFhirImportInput) => Promise<SubmitAndPollResult>;
|
|
33
|
+
upsertRelatedPersonAndPoll?: (ctx: RouteContext, input: RelatedPersonUpsertInput) => Promise<SubmitAndPollResult>;
|
|
34
|
+
generateDigitalTwinFromSubjectData?: (ctx: RouteContext, input: DigitalTwinGenerationInput) => Promise<SubmitAndPollResult>;
|
|
35
|
+
searchClinicalBundle?: (ctx: RouteContext, input: ClinicalBundleSearchInput) => Promise<SubmitAndPollResult>;
|
|
36
|
+
submitBatch?: (submitPath: string, payload: SubmitPayload) => Promise<SubmitResponse>;
|
|
37
|
+
pollUntilComplete?: (pollPath: string, request: AsyncPollRequest, pollOptions?: PollOptions) => Promise<PollResult>;
|
|
38
|
+
submitAndPoll?: (submitPath: string, pollPath: string, payload: SubmitPayload, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated Prefer `RuntimeClient`.
|
|
42
|
+
*/
|
|
43
|
+
export type NodeRuntimeClient = RuntimeClient;
|
|
44
|
+
export declare function requireClientMethod<T extends keyof RuntimeClient>(client: RuntimeClient, method: T): NonNullable<RuntimeClient[T]>;
|
|
45
|
+
export declare function submitAndPollWithMethods(methods: Pick<RuntimeClient, 'submitBatch' | 'pollUntilComplete'>, submitPath: string, pollPath: string, payload: SubmitPayload, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
46
|
+
export declare function canClientSubmitAndPoll(client: NodeRuntimeClient): boolean;
|
|
47
|
+
export declare function submitAndPollWithClient(client: RuntimeClient, submitPath: string, pollPath: string, payload: SubmitPayload, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function requireClientMethod(client, method) {
|
|
2
|
+
const candidate = client[method];
|
|
3
|
+
if (typeof candidate !== 'function') {
|
|
4
|
+
throw new Error(`RuntimeClient does not implement '${String(method)}'.`);
|
|
5
|
+
}
|
|
6
|
+
return candidate.bind(client);
|
|
7
|
+
}
|
|
8
|
+
export async function submitAndPollWithMethods(methods, submitPath, pollPath, payload, pollOptions) {
|
|
9
|
+
const thid = requireSubmitPayloadThid(payload);
|
|
10
|
+
const submit = await requireClientMethod(methods, 'submitBatch')(submitPath, payload);
|
|
11
|
+
const poll = await requireClientMethod(methods, 'pollUntilComplete')(pollPath, { thid }, pollOptions);
|
|
12
|
+
return { submit, poll };
|
|
13
|
+
}
|
|
14
|
+
export function canClientSubmitAndPoll(client) {
|
|
15
|
+
return typeof client.submitAndPoll === 'function';
|
|
16
|
+
}
|
|
17
|
+
export async function submitAndPollWithClient(client, submitPath, pollPath, payload, pollOptions) {
|
|
18
|
+
const thid = requireSubmitPayloadThid(payload);
|
|
19
|
+
const normalizedPayload = { ...payload, thid };
|
|
20
|
+
if (canClientSubmitAndPoll(client)) {
|
|
21
|
+
return requireClientMethod(client, 'submitAndPoll')(submitPath, pollPath, normalizedPayload, pollOptions);
|
|
22
|
+
}
|
|
23
|
+
return submitAndPollWithMethods(client, submitPath, pollPath, normalizedPayload, pollOptions);
|
|
24
|
+
}
|
|
25
|
+
function requireSubmitPayloadThid(payload) {
|
|
26
|
+
const thid = String(payload.thid || '').trim();
|
|
27
|
+
if (!thid) {
|
|
28
|
+
throw new Error('submitAndPoll requires payload.thid.');
|
|
29
|
+
}
|
|
30
|
+
return thid;
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ControllerBindingInput } from 'gdc-common-utils-ts/models';
|
|
2
|
+
import { type NodeRuntimeClient, type PollOptions, type SubmitAndPollResult, type SubmitPayload } from './client-port.js';
|
|
3
|
+
import type { HostRouteContext, LegalOrganizationOrderInput } from '../host-onboarding.js';
|
|
4
|
+
export declare class HostOnboardingSdk {
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(client: NodeRuntimeClient);
|
|
7
|
+
activateOrganizationInGatewayFromIcaProof(hostCtx: HostRouteContext, input: {
|
|
8
|
+
vpToken: string;
|
|
9
|
+
controller?: ControllerBindingInput;
|
|
10
|
+
additionalClaims?: Record<string, unknown>;
|
|
11
|
+
}, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
12
|
+
confirmLegalOrganizationOrder(hostCtx: HostRouteContext, input: LegalOrganizationOrderInput, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
13
|
+
submitAndPoll(submitPath: string, pollPath: string, payload: SubmitPayload, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { requireClientMethod, submitAndPollWithClient, } from './client-port.js';
|
|
2
|
+
export class HostOnboardingSdk {
|
|
3
|
+
constructor(client) {
|
|
4
|
+
this.client = client;
|
|
5
|
+
}
|
|
6
|
+
activateOrganizationInGatewayFromIcaProof(hostCtx, input, pollOptions) {
|
|
7
|
+
return requireClientMethod(this.client, 'activateOrganizationInGatewayFromIcaProof')(hostCtx, input, pollOptions);
|
|
8
|
+
}
|
|
9
|
+
confirmLegalOrganizationOrder(hostCtx, input, pollOptions) {
|
|
10
|
+
return requireClientMethod(this.client, 'confirmLegalOrganizationOrder')(hostCtx, input, pollOptions);
|
|
11
|
+
}
|
|
12
|
+
submitAndPoll(submitPath, pollPath, payload, pollOptions) {
|
|
13
|
+
return submitAndPollWithClient(this.client, submitPath, pollPath, payload, pollOptions);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type NodeRuntimeClient, type PollOptions, type SubmitAndPollResult, type SubmitPayload } from './client-port.js';
|
|
2
|
+
import type { IndividualOrganizationConfirmOrderInput, RouteContext } from '../individual-onboarding.js';
|
|
3
|
+
import type { IndividualOrganizationBootstrapInput, IndividualOrganizationStartResult } from '../individual-start.js';
|
|
4
|
+
import type { CommunicationIngestionInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IpsOrFhirImportInput, RelatedPersonUpsertInput } from '../resource-operations.js';
|
|
5
|
+
import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
|
|
6
|
+
/**
|
|
7
|
+
* Individual-controller oriented facade over a `NodeRuntimeClient`.
|
|
8
|
+
*
|
|
9
|
+
* It groups the most common individual subject flows: organization/index
|
|
10
|
+
* bootstrap, consent, IPS/FHIR ingestion, digital twin generation, and token requests.
|
|
11
|
+
*/
|
|
12
|
+
export declare class IndividualControllerSdk {
|
|
13
|
+
private readonly client;
|
|
14
|
+
/**
|
|
15
|
+
* @param client Runtime client implementation used to submit and poll GW flows.
|
|
16
|
+
*/
|
|
17
|
+
constructor(client: NodeRuntimeClient);
|
|
18
|
+
/**
|
|
19
|
+
* Starts the individual onboarding/bootstrap flow.
|
|
20
|
+
*/
|
|
21
|
+
startIndividualOrganization(input: IndividualOrganizationBootstrapInput): Promise<IndividualOrganizationStartResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Confirms the order returned by `startIndividualOrganization(...)`.
|
|
24
|
+
*/
|
|
25
|
+
confirmIndividualOrganizationOrder(input: IndividualOrganizationConfirmOrderInput): Promise<SubmitAndPollResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Grants access to a professional through a consent flow.
|
|
28
|
+
*/
|
|
29
|
+
grantProfessionalAccess(ctx: RouteContext, input: GrantProfessionalAccessInput): Promise<GrantProfessionalAccessResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Imports a FHIR/IPS payload and waits until it is indexed.
|
|
32
|
+
*/
|
|
33
|
+
importIpsOrFhirAndUpdateIndex(ctx: RouteContext, input: IpsOrFhirImportInput): Promise<SubmitAndPollResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Creates or updates a `RelatedPerson` for non-employee caregivers or family members.
|
|
36
|
+
*/
|
|
37
|
+
upsertRelatedPersonAndPoll(ctx: RouteContext, input: RelatedPersonUpsertInput): Promise<SubmitAndPollResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Ingests a FHIR `Communication` and waits for indexing.
|
|
40
|
+
*/
|
|
41
|
+
ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Generates a digital twin projection from subject data.
|
|
44
|
+
*/
|
|
45
|
+
generateDigitalTwinFromSubjectData(ctx: RouteContext, input: DigitalTwinGenerationInput): Promise<SubmitAndPollResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Requests a SMART/OpenID token for subsequent data access flows.
|
|
48
|
+
*/
|
|
49
|
+
requestSmartToken(input: SmartTokenRequestInput): Promise<SmartTokenExchangeResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Low-level escape hatch for direct submit/poll flows.
|
|
52
|
+
*/
|
|
53
|
+
submitAndPoll(submitPath: string, pollPath: string, payload: SubmitPayload, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
54
|
+
}
|