gdc-sdk-node-ts 2.0.7 → 2.0.9
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 +33 -0
- package/dist/constants/lifecycle.d.ts +2 -0
- package/dist/constants/lifecycle.js +2 -0
- package/dist/device-activation.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/node-runtime-client.d.ts +14 -0
- package/dist/node-runtime-client.js +29 -0
- package/dist/orchestration/client-port.d.ts +1 -0
- package/dist/orchestration/organization-controller-sdk.d.ts +5 -0
- package/dist/orchestration/organization-controller-sdk.js +7 -0
- package/dist/organization-controller-recovery.d.ts +31 -0
- package/dist/organization-controller-recovery.js +48 -0
- package/dist/profile-workspace.d.ts +2 -68
- package/dist/profile-workspace.js +3 -106
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -682,6 +682,19 @@ For legal-organization onboarding from a Node BFF/runtime, keep the host steps s
|
|
|
682
682
|
Use `OrganizationControllerSdk.submitLegalOrganizationVerificationTransaction(...)` or
|
|
683
683
|
`NodeHttpClient.submitLegalOrganizationVerificationTransaction(...)` for step 1.
|
|
684
684
|
|
|
685
|
+
Existing-tenant recovery/reverification:
|
|
686
|
+
|
|
687
|
+
- use `OrganizationControllerSdk.submitLegalOrganizationIssue(...)` or
|
|
688
|
+
`NodeHttpClient.submitLegalOrganizationIssue(...)` to refresh the ICA-backed
|
|
689
|
+
verification for an already registered tenant without creating a new Offer
|
|
690
|
+
- GW is expected to return one new controller activation code as
|
|
691
|
+
`org.schema.IndividualProduct.serialNumber`
|
|
692
|
+
- then continue with the existing helper chain:
|
|
693
|
+
`recoverOrganizationControllerWithIssueWithDeps(...)`
|
|
694
|
+
or directly `_exchange -> _dcr`
|
|
695
|
+
- for a reproducible local/staging runtime check, use:
|
|
696
|
+
`npm run test:e2e:live-gw:issue-recovery`
|
|
697
|
+
|
|
685
698
|
Rules:
|
|
686
699
|
|
|
687
700
|
- `_transaction` and `_activate` are different flows
|
|
@@ -714,3 +727,23 @@ Live E2E legal PDF source:
|
|
|
714
727
|
- public URL: set `LIVE_GW_HOST_VERIFICATION_PDF_URL=https://.../file.pdf`
|
|
715
728
|
- if both are present, the live suite prefers `LIVE_GW_HOST_VERIFICATION_PDF_URL`
|
|
716
729
|
- Dropbox-style links are normalized to `dl=1` direct-download mode automatically
|
|
730
|
+
|
|
731
|
+
Recovery-specific live rule:
|
|
732
|
+
|
|
733
|
+
- `Organization/_issue` can succeed and still be followed by `_exchange` failure
|
|
734
|
+
if the controller `id_token` is not production-shaped enough
|
|
735
|
+
- the current GW `_exchange` path expects at least:
|
|
736
|
+
- syntactically valid JWT format
|
|
737
|
+
- `tenant_id` claim matching the target tenant
|
|
738
|
+
- the bundled recovery runner generates a syntactically valid demo JWT if
|
|
739
|
+
`CONTROLLER_ID_TOKEN` is not provided, but production/staging should use a
|
|
740
|
+
real IdP-issued token
|
|
741
|
+
|
|
742
|
+
Minimal live recovery command:
|
|
743
|
+
|
|
744
|
+
```bash
|
|
745
|
+
PDF_PATH=/Users/fernando/GITS/gdc-workspace/examples/TEST-A4-Antifraud.pdf \
|
|
746
|
+
BASE_URL=http://127.0.0.1:3000 \
|
|
747
|
+
TENANT_ID=acme-id \
|
|
748
|
+
npm run test:e2e:live-gw:issue-recovery
|
|
749
|
+
```
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
export declare const GwCoreLifecycleAction: Readonly<{
|
|
10
10
|
readonly Batch: "_batch";
|
|
11
11
|
readonly BatchResponse: "_batch-response";
|
|
12
|
+
readonly Issue: "_issue";
|
|
13
|
+
readonly IssueResponse: "_issue-response";
|
|
12
14
|
readonly Transaction: "_transaction";
|
|
13
15
|
readonly TransactionResponse: "_transaction-response";
|
|
14
16
|
readonly Disable: "_disable";
|
|
@@ -11,6 +11,8 @@ import { LifecycleRequestType } from 'gdc-common-utils-ts';
|
|
|
11
11
|
export const GwCoreLifecycleAction = Object.freeze({
|
|
12
12
|
Batch: '_batch',
|
|
13
13
|
BatchResponse: '_batch-response',
|
|
14
|
+
Issue: '_issue',
|
|
15
|
+
IssueResponse: '_issue-response',
|
|
14
16
|
Transaction: '_transaction',
|
|
15
17
|
TransactionResponse: '_transaction-response',
|
|
16
18
|
Disable: '_disable',
|
|
@@ -14,6 +14,7 @@ export async function activateEmployeeDeviceWithActivationCodeWithDeps(deps) {
|
|
|
14
14
|
}
|
|
15
15
|
const dcrPayload = {
|
|
16
16
|
thid: `dcr-${createRuntimeUuid()}`,
|
|
17
|
+
code: deps.input.activationCode,
|
|
17
18
|
...deps.input.dcrPayload,
|
|
18
19
|
};
|
|
19
20
|
const dcr = await deps.submitAndPollWithBearerToken(initialAccessToken, deps.identityDeviceDcrPath(deps.routeCtx), deps.identityDeviceDcrPollPath(deps.routeCtx), dcrPayload, deps.input.pollOptions);
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from './family-organization-search.js';
|
|
|
13
13
|
export * from './family-organization-registration.js';
|
|
14
14
|
export * from './individual-onboarding.js';
|
|
15
15
|
export * from './device-activation.js';
|
|
16
|
+
export * from './organization-controller-recovery.js';
|
|
16
17
|
export * from './smart-token.js';
|
|
17
18
|
export * from './order-offer-summary.js';
|
|
18
19
|
export * from './organization-license-order.js';
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './family-organization-search.js';
|
|
|
14
14
|
export * from './family-organization-registration.js';
|
|
15
15
|
export * from './individual-onboarding.js';
|
|
16
16
|
export * from './device-activation.js';
|
|
17
|
+
export * from './organization-controller-recovery.js';
|
|
17
18
|
export * from './smart-token.js';
|
|
18
19
|
export * from './order-offer-summary.js';
|
|
19
20
|
export * from './organization-license-order.js';
|
|
@@ -127,6 +127,16 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
|
|
|
127
127
|
* - `_activate` remains available only for the older ICA `_verify` based flow
|
|
128
128
|
*/
|
|
129
129
|
submitLegalOrganizationVerificationTransaction(hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
130
|
+
/**
|
|
131
|
+
* Starts the host-side existing-tenant legal-organization reissue flow that
|
|
132
|
+
* GW CORE forwards to ICA `_verify`.
|
|
133
|
+
*
|
|
134
|
+
* Semantics:
|
|
135
|
+
* - reuse the same signed evidence/controller binding contract as `_transaction`
|
|
136
|
+
* - do not create a new Offer
|
|
137
|
+
* - expect GW CORE to reissue one controller activation code in the response
|
|
138
|
+
*/
|
|
139
|
+
submitLegalOrganizationIssue(hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
130
140
|
/**
|
|
131
141
|
* Submits one tenant-scoped DID document binding request.
|
|
132
142
|
*
|
|
@@ -411,6 +421,8 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
|
|
|
411
421
|
private requireHostRouteContext;
|
|
412
422
|
hostRegistryOrganizationTransactionPath(ctx?: HostRouteContext): string;
|
|
413
423
|
hostRegistryOrganizationTransactionPollPath(ctx?: HostRouteContext): string;
|
|
424
|
+
hostRegistryOrganizationIssuePath(ctx?: HostRouteContext): string;
|
|
425
|
+
hostRegistryOrganizationIssuePollPath(ctx?: HostRouteContext): string;
|
|
414
426
|
hostRegistryOrganizationActivatePath(ctx?: HostRouteContext): string;
|
|
415
427
|
hostRegistryOrganizationActivatePollPath(ctx?: HostRouteContext): string;
|
|
416
428
|
hostRegistryOrganizationDisablePath(ctx?: HostRouteContext): string;
|
|
@@ -465,6 +477,8 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
|
|
|
465
477
|
individualBundleSearchPollPath(ctx: RouteContext): string;
|
|
466
478
|
identityTokenExchangePath(ctx: RouteContext): string;
|
|
467
479
|
identityTokenExchangePollPath(ctx: RouteContext): string;
|
|
480
|
+
identityDeviceDcrPath(ctx: RouteContext): string;
|
|
481
|
+
identityDeviceDcrPollPath(ctx: RouteContext): string;
|
|
468
482
|
identityOpenIdSmartTokenPath(ctx: RouteContext): string;
|
|
469
483
|
identityOpenIdSmartTokenPollPath(ctx: RouteContext): string;
|
|
470
484
|
private appendHttpTrace;
|
|
@@ -126,6 +126,27 @@ export class HttpRuntimeClient {
|
|
|
126
126
|
});
|
|
127
127
|
return this.submitAndPoll(this.hostRegistryOrganizationTransactionPath(hostCtx), this.hostRegistryOrganizationTransactionPollPath(hostCtx), payload, pollOptions);
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Starts the host-side existing-tenant legal-organization reissue flow that
|
|
131
|
+
* GW CORE forwards to ICA `_verify`.
|
|
132
|
+
*
|
|
133
|
+
* Semantics:
|
|
134
|
+
* - reuse the same signed evidence/controller binding contract as `_transaction`
|
|
135
|
+
* - do not create a new Offer
|
|
136
|
+
* - expect GW CORE to reissue one controller activation code in the response
|
|
137
|
+
*/
|
|
138
|
+
async submitLegalOrganizationIssue(hostCtx, input, pollOptions) {
|
|
139
|
+
const thid = `organization-issue-${runtimeUuid()}`;
|
|
140
|
+
const jti = `organization-issue-jti-${runtimeUuid()}`;
|
|
141
|
+
const verificationBundle = buildLegalOrganizationVerificationGatewayRequestBundle(input);
|
|
142
|
+
const payload = this.wrapBundleAsGatewayTransactionMessage({
|
|
143
|
+
thid,
|
|
144
|
+
jti,
|
|
145
|
+
hostCtx,
|
|
146
|
+
bundle: verificationBundle,
|
|
147
|
+
});
|
|
148
|
+
return this.submitAndPoll(this.hostRegistryOrganizationIssuePath(hostCtx), this.hostRegistryOrganizationIssuePollPath(hostCtx), payload, pollOptions);
|
|
149
|
+
}
|
|
129
150
|
/**
|
|
130
151
|
* Submits one tenant-scoped DID document binding request.
|
|
131
152
|
*
|
|
@@ -895,6 +916,8 @@ export class HttpRuntimeClient {
|
|
|
895
916
|
}
|
|
896
917
|
hostRegistryOrganizationTransactionPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Transaction); }
|
|
897
918
|
hostRegistryOrganizationTransactionPollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.TransactionResponse); }
|
|
919
|
+
hostRegistryOrganizationIssuePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Issue); }
|
|
920
|
+
hostRegistryOrganizationIssuePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.IssueResponse); }
|
|
898
921
|
hostRegistryOrganizationActivatePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', '_activate'); }
|
|
899
922
|
hostRegistryOrganizationActivatePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', '_activate-response'); }
|
|
900
923
|
hostRegistryOrganizationDisablePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Disable); }
|
|
@@ -959,6 +982,12 @@ export class HttpRuntimeClient {
|
|
|
959
982
|
identityTokenExchangePollPath(ctx) {
|
|
960
983
|
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_exchange-response`;
|
|
961
984
|
}
|
|
985
|
+
identityDeviceDcrPath(ctx) {
|
|
986
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_dcr`;
|
|
987
|
+
}
|
|
988
|
+
identityDeviceDcrPollPath(ctx) {
|
|
989
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_dcr-response`;
|
|
990
|
+
}
|
|
962
991
|
identityOpenIdSmartTokenPath(ctx) {
|
|
963
992
|
return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/token`;
|
|
964
993
|
}
|
|
@@ -54,6 +54,7 @@ export type NodeOrganizationDidBindingInput = OrganizationDidBindingInput;
|
|
|
54
54
|
*/
|
|
55
55
|
export type RuntimeClient = {
|
|
56
56
|
submitLegalOrganizationVerificationTransaction?: (hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
57
|
+
submitLegalOrganizationIssue?: (hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
57
58
|
submitOrganizationDidBinding?: (ctx: RouteContext, input: NodeOrganizationDidBindingInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
58
59
|
activateOrganizationInGatewayFromIcaProof?: (hostCtx: HostRouteContext, input: NodeOrganizationActivationInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
59
60
|
confirmLegalOrganizationOrder?: (hostCtx: HostRouteContext, input: LegalOrganizationOrderInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
@@ -29,6 +29,11 @@ export declare class OrganizationControllerSdk {
|
|
|
29
29
|
* - `_activate` remains only for the legacy ICA `_verify` compatibility path
|
|
30
30
|
*/
|
|
31
31
|
submitLegalOrganizationVerificationTransaction(hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Starts the host-side existing-tenant legal-organization reissue flow that
|
|
34
|
+
* refreshes verification and reissues one controller activation code.
|
|
35
|
+
*/
|
|
36
|
+
submitLegalOrganizationIssue(hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions): Promise<SubmitAndPollResult>;
|
|
32
37
|
/**
|
|
33
38
|
* Binds the current tenant organization DID document to one public alias
|
|
34
39
|
* view.
|
|
@@ -28,6 +28,13 @@ export class OrganizationControllerSdk {
|
|
|
28
28
|
submitLegalOrganizationVerificationTransaction(hostCtx, input, pollOptions) {
|
|
29
29
|
return requireClientMethod(this.client, 'submitLegalOrganizationVerificationTransaction')(hostCtx, input, pollOptions);
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Starts the host-side existing-tenant legal-organization reissue flow that
|
|
33
|
+
* refreshes verification and reissues one controller activation code.
|
|
34
|
+
*/
|
|
35
|
+
submitLegalOrganizationIssue(hostCtx, input, pollOptions) {
|
|
36
|
+
return requireClientMethod(this.client, 'submitLegalOrganizationIssue')(hostCtx, input, pollOptions);
|
|
37
|
+
}
|
|
31
38
|
/**
|
|
32
39
|
* Binds the current tenant organization DID document to one public alias
|
|
33
40
|
* view.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { NodeLegalOrganizationVerificationTransactionInput, PollOptions, SubmitAndPollResult } from './orchestration/client-port.js';
|
|
2
|
+
import type { HostRouteContext } from './host-onboarding.js';
|
|
3
|
+
import type { RouteContext } from './individual-onboarding.js';
|
|
4
|
+
import type { EmployeeDeviceActivationResult } from './device-activation.js';
|
|
5
|
+
export type OrganizationControllerRecoveryInput = {
|
|
6
|
+
issueInput: NodeLegalOrganizationVerificationTransactionInput;
|
|
7
|
+
controllerIdToken: string;
|
|
8
|
+
dcrPayload: Record<string, unknown>;
|
|
9
|
+
issuePollOptions?: PollOptions;
|
|
10
|
+
activationPollOptions?: PollOptions;
|
|
11
|
+
};
|
|
12
|
+
export type OrganizationControllerRecoveryResult = {
|
|
13
|
+
issue: SubmitAndPollResult;
|
|
14
|
+
activationCode: string;
|
|
15
|
+
activation: EmployeeDeviceActivationResult;
|
|
16
|
+
};
|
|
17
|
+
type RecoverOrganizationControllerWithIssueDeps = {
|
|
18
|
+
hostCtx: HostRouteContext;
|
|
19
|
+
tenantCtx: RouteContext;
|
|
20
|
+
input: OrganizationControllerRecoveryInput;
|
|
21
|
+
submitLegalOrganizationIssue: (hostCtx: HostRouteContext, input: NodeLegalOrganizationVerificationTransactionInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
22
|
+
identityTokenExchangePath: (ctx: RouteContext) => string;
|
|
23
|
+
identityTokenExchangePollPath: (ctx: RouteContext) => string;
|
|
24
|
+
identityDeviceDcrPath: (ctx: RouteContext) => string;
|
|
25
|
+
identityDeviceDcrPollPath: (ctx: RouteContext) => string;
|
|
26
|
+
submitAndPollWithBearerToken: (bearerToken: string | undefined, submitPath: string, pollPath: string, payload: {
|
|
27
|
+
thid?: string;
|
|
28
|
+
} & Record<string, unknown>, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
|
|
29
|
+
};
|
|
30
|
+
export declare function recoverOrganizationControllerWithIssueWithDeps(deps: RecoverOrganizationControllerWithIssueDeps): Promise<OrganizationControllerRecoveryResult>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { activateEmployeeDeviceWithActivationCodeWithDeps } from './device-activation.js';
|
|
3
|
+
export async function recoverOrganizationControllerWithIssueWithDeps(deps) {
|
|
4
|
+
const issue = await deps.submitLegalOrganizationIssue(deps.hostCtx, deps.input.issueInput, deps.input.issuePollOptions);
|
|
5
|
+
const activationCode = readActivationCodeFromIssueResult(issue);
|
|
6
|
+
if (!activationCode) {
|
|
7
|
+
throw new Error('recoverOrganizationControllerWithIssue: missing org.schema.IndividualProduct.serialNumber in Organization/_issue response.');
|
|
8
|
+
}
|
|
9
|
+
const activation = await activateEmployeeDeviceWithActivationCodeWithDeps({
|
|
10
|
+
routeCtx: deps.tenantCtx,
|
|
11
|
+
input: {
|
|
12
|
+
activationCode,
|
|
13
|
+
idToken: deps.input.controllerIdToken,
|
|
14
|
+
dcrPayload: deps.input.dcrPayload,
|
|
15
|
+
pollOptions: deps.input.activationPollOptions,
|
|
16
|
+
},
|
|
17
|
+
identityTokenExchangePath: deps.identityTokenExchangePath,
|
|
18
|
+
identityTokenExchangePollPath: deps.identityTokenExchangePollPath,
|
|
19
|
+
identityDeviceDcrPath: deps.identityDeviceDcrPath,
|
|
20
|
+
identityDeviceDcrPollPath: deps.identityDeviceDcrPollPath,
|
|
21
|
+
submitAndPollWithBearerToken: deps.submitAndPollWithBearerToken,
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
issue,
|
|
25
|
+
activationCode,
|
|
26
|
+
activation,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function readActivationCodeFromIssueResult(result) {
|
|
30
|
+
const pollBody = (result?.poll?.body || {});
|
|
31
|
+
const body = (pollBody.body || pollBody);
|
|
32
|
+
const data = Array.isArray(body.data) ? body.data : Array.isArray(pollBody.data) ? pollBody.data : [];
|
|
33
|
+
const firstEntry = data[0] || {};
|
|
34
|
+
const claims = firstEntry.meta?.claims;
|
|
35
|
+
const activationCode = String(claims?.['org.schema.IndividualProduct.serialNumber'] || '').trim();
|
|
36
|
+
if (activationCode) {
|
|
37
|
+
return activationCode;
|
|
38
|
+
}
|
|
39
|
+
const diagnostics = firstEntry.response?.outcome
|
|
40
|
+
?.issue
|
|
41
|
+
?.map((issue) => String(issue?.diagnostics || '').trim())
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.join(' | ');
|
|
44
|
+
if (diagnostics) {
|
|
45
|
+
throw new Error(`recoverOrganizationControllerWithIssue: Organization/_issue failed: ${diagnostics}`);
|
|
46
|
+
}
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { CommunicationAttachedBundleSession, IndividualBundleVault, buildVitalSignObservationClaims, createSummaryOperationRequestParameters, createSummaryOperationRequestParametersResource, summarizeClinicalBundle, toClinicalResourceExpandedViews, type BuildVitalSignObservationClaimsInput } from 'gdc-common-utils-ts';
|
|
2
|
-
import { type FhirDocumentFacade, type FhirBundleEntryLike, type FhirDocumentEntryQuery, type FhirDocumentSection, type FhirDocumentFamilyQuery, type FhirDocumentResourceQuery, type FhirDocumentSectionCounts, type FhirDocumentSectionSummary, type FhirResourceLike } from 'gdc-sdk-core-ts';
|
|
3
2
|
import type { BackendOrganizationControllerProfile, BackendProfessionalProfile } from './backend-profile-runtime.js';
|
|
4
|
-
type LocalTextAndIntDisplay = ReturnType<FhirDocumentFacade['getLocalTextAndIntDisplay']>;
|
|
5
|
-
type NarrativeResult = ReturnType<FhirDocumentFacade['getNarrative']>;
|
|
6
3
|
export type IpsRequestDraft = Readonly<{
|
|
7
4
|
subjectId: string;
|
|
8
5
|
purpose?: string;
|
|
@@ -16,74 +13,11 @@ export type ProcessedClinicalBundleResponse = Readonly<{
|
|
|
16
13
|
totalSections: number;
|
|
17
14
|
totalResources: number;
|
|
18
15
|
totalResourcesInSection: Readonly<Record<string, number>>;
|
|
16
|
+
totalNarratives: number;
|
|
17
|
+
totalNotes: number;
|
|
19
18
|
summary: ReturnType<typeof summarizeClinicalBundle>;
|
|
20
19
|
views: ReturnType<typeof toClinicalResourceExpandedViews>;
|
|
21
|
-
sectionCounts: FhirDocumentSectionCounts;
|
|
22
|
-
sectionSummary: FhirDocumentSectionSummary;
|
|
23
|
-
getSections: () => FhirDocumentSection[];
|
|
24
|
-
getEntries: (input?: FhirDocumentEntryQuery) => FhirBundleEntryLike[];
|
|
25
|
-
getResources: (query?: string | FhirDocumentResourceQuery) => FhirResourceLike[];
|
|
26
|
-
getByDates: (query: string | FhirDocumentResourceQuery, start?: string, end?: string) => FhirResourceLike[];
|
|
27
|
-
getSectionCounts: (input?: {
|
|
28
|
-
sections?: readonly string[];
|
|
29
|
-
}) => FhirDocumentSectionCounts;
|
|
30
|
-
getSectionSummary: (input?: {
|
|
31
|
-
sections?: readonly string[];
|
|
32
|
-
}) => FhirDocumentSectionSummary;
|
|
33
|
-
getLocalTextAndIntDisplay: (resourceOrEntry: FhirResourceLike | FhirBundleEntryLike) => LocalTextAndIntDisplay;
|
|
34
|
-
getXhtmlOrDerived: (resourceOrEntry: FhirResourceLike | FhirBundleEntryLike) => string | undefined;
|
|
35
|
-
getNarrative: (resourceOrEntry: FhirResourceLike | FhirBundleEntryLike) => NarrativeResult;
|
|
36
|
-
getAllergies: (query?: FhirDocumentFamilyQuery & {
|
|
37
|
-
clinicalStatus?: readonly string[];
|
|
38
|
-
verificationStatus?: readonly string[];
|
|
39
|
-
criticality?: readonly string[];
|
|
40
|
-
}) => FhirBundleEntryLike[];
|
|
41
|
-
getConditions: (query?: FhirDocumentFamilyQuery & {
|
|
42
|
-
clinicalStatus?: readonly string[];
|
|
43
|
-
verificationStatus?: readonly string[];
|
|
44
|
-
severity?: readonly string[];
|
|
45
|
-
}) => FhirBundleEntryLike[];
|
|
46
|
-
getMedications: (query?: FhirDocumentFamilyQuery & {
|
|
47
|
-
status?: readonly string[];
|
|
48
|
-
}) => FhirBundleEntryLike[];
|
|
49
|
-
getVitalSigns: (query?: FhirDocumentFamilyQuery & {
|
|
50
|
-
code?: readonly string[];
|
|
51
|
-
}) => FhirBundleEntryLike[];
|
|
52
|
-
reader: ClinicalBundleQueryBuilder;
|
|
53
20
|
}>;
|
|
54
|
-
export type ClinicalBundleQueryBuilder = Readonly<{
|
|
55
|
-
allSections: () => ClinicalBundleQueryBuilder;
|
|
56
|
-
inSections: (sections?: readonly string[]) => ClinicalBundleQueryBuilder;
|
|
57
|
-
between: (start?: string, end?: string) => ClinicalBundleQueryBuilder;
|
|
58
|
-
matchingText: (searchText?: string) => ClinicalBundleQueryBuilder;
|
|
59
|
-
paginate: (input?: {
|
|
60
|
-
count?: number;
|
|
61
|
-
page?: number;
|
|
62
|
-
offset?: number;
|
|
63
|
-
}) => ClinicalBundleQueryBuilder;
|
|
64
|
-
getEntries: (resourceTypes?: readonly string[]) => FhirBundleEntryLike[];
|
|
65
|
-
getResources: (resourceType?: string) => FhirResourceLike[];
|
|
66
|
-
getAllergies: (query?: {
|
|
67
|
-
clinicalStatus?: readonly string[];
|
|
68
|
-
verificationStatus?: readonly string[];
|
|
69
|
-
criticality?: readonly string[];
|
|
70
|
-
}) => FhirBundleEntryLike[];
|
|
71
|
-
getConditions: (query?: {
|
|
72
|
-
clinicalStatus?: readonly string[];
|
|
73
|
-
verificationStatus?: readonly string[];
|
|
74
|
-
severity?: readonly string[];
|
|
75
|
-
}) => FhirBundleEntryLike[];
|
|
76
|
-
getMedications: (query?: {
|
|
77
|
-
status?: readonly string[];
|
|
78
|
-
}) => FhirBundleEntryLike[];
|
|
79
|
-
getVitalSigns: (query?: {
|
|
80
|
-
code?: readonly string[];
|
|
81
|
-
}) => FhirBundleEntryLike[];
|
|
82
|
-
getSectionCounts: () => FhirDocumentSectionCounts;
|
|
83
|
-
}>;
|
|
84
|
-
/**
|
|
85
|
-
* Builds one reusable high-level clinical response view over the bundle body.
|
|
86
|
-
*/
|
|
87
21
|
declare function buildProcessedClinicalBundleResponse(body: unknown): ProcessedClinicalBundleResponse;
|
|
88
22
|
declare class ProfessionalSubjectIpsWorkspace {
|
|
89
23
|
private readonly subjectId;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
import { CommunicationAttachedBundleSession, IndividualBundleVault, VaultMemRepository, buildVitalSignObservationClaims,
|
|
3
|
-
import { createFhirDocumentFacade, } from 'gdc-sdk-core-ts';
|
|
2
|
+
import { CommunicationAttachedBundleSession, IndividualBundleVault, VaultMemRepository, buildVitalSignObservationClaims, createConsentAccessEditor, createInvoiceBundleEditor, createSummaryOperationRequestParameters, createSummaryOperationRequestParametersResource, createSummaryOperationRequestReferencePath, readEmployeeSearchResults, summarizeClinicalBundle, summarizeLicenseListRecords, toClinicalResourceExpandedViews, } from 'gdc-common-utils-ts';
|
|
4
3
|
function normalizeSectionList(sectionList) {
|
|
5
4
|
return Array.from(new Set((sectionList || []).map((item) => String(item || '').trim()).filter(Boolean)));
|
|
6
5
|
}
|
|
@@ -22,121 +21,19 @@ function buildClinicalSectionCounts(views) {
|
|
|
22
21
|
}
|
|
23
22
|
return out;
|
|
24
23
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Normalizes the shared claims-first bundle examples into one FHIR document
|
|
27
|
-
* bundle so the section-aware facade can read `Composition.section` without
|
|
28
|
-
* teaching raw claim plumbing to SDK consumers.
|
|
29
|
-
*/
|
|
30
|
-
function normalizeClinicalDocumentBundle(bundle) {
|
|
31
|
-
if (bundle?.resourceType === 'Bundle' && Array.isArray(bundle?.entry)) {
|
|
32
|
-
return bundle;
|
|
33
|
-
}
|
|
34
|
-
const claimsList = extractResourceMetaClaimsFromBundle(bundle).map((item) => item.claims);
|
|
35
|
-
if (claimsList.length === 0) {
|
|
36
|
-
return bundle;
|
|
37
|
-
}
|
|
38
|
-
const subjectDid = claimsList
|
|
39
|
-
.map((claims) => {
|
|
40
|
-
const subjectKeys = Object.keys(claims).filter((key) => String(key || '').toLowerCase().endsWith('.subject'));
|
|
41
|
-
for (const key of subjectKeys) {
|
|
42
|
-
const value = claims[key];
|
|
43
|
-
if (typeof value === 'string' && value.trim())
|
|
44
|
-
return value.trim();
|
|
45
|
-
}
|
|
46
|
-
return '';
|
|
47
|
-
})
|
|
48
|
-
.find(Boolean);
|
|
49
|
-
return buildBundleDocumentFromClaims({
|
|
50
|
-
claimsList,
|
|
51
|
-
...(subjectDid ? { subjectDid } : {}),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Creates one immutable high-level reader that keeps section/date/text/paging
|
|
56
|
-
* filters chainable across generic and family-specific clinical queries.
|
|
57
|
-
*/
|
|
58
|
-
function createClinicalBundleQueryBuilder(facade, state = {}) {
|
|
59
|
-
const next = (patch) => createClinicalBundleQueryBuilder(facade, {
|
|
60
|
-
...state,
|
|
61
|
-
...patch,
|
|
62
|
-
});
|
|
63
|
-
return {
|
|
64
|
-
allSections: () => next({ sections: [] }),
|
|
65
|
-
inSections: (sections) => next({ sections: sections ? [...sections] : [] }),
|
|
66
|
-
between: (start, end) => next({ start, end }),
|
|
67
|
-
matchingText: (searchText) => next({ searchText }),
|
|
68
|
-
paginate: (input) => next({
|
|
69
|
-
count: input?.count,
|
|
70
|
-
page: input?.page,
|
|
71
|
-
offset: input?.offset,
|
|
72
|
-
}),
|
|
73
|
-
getEntries: (resourceTypes) => facade.getEntries({
|
|
74
|
-
sections: state.sections,
|
|
75
|
-
resourceTypes,
|
|
76
|
-
start: state.start,
|
|
77
|
-
end: state.end,
|
|
78
|
-
searchText: state.searchText,
|
|
79
|
-
count: state.count,
|
|
80
|
-
page: state.page,
|
|
81
|
-
offset: state.offset,
|
|
82
|
-
}),
|
|
83
|
-
getResources: (resourceType) => facade.getResources({
|
|
84
|
-
...state,
|
|
85
|
-
...(resourceType ? { resourceType } : {}),
|
|
86
|
-
}),
|
|
87
|
-
getAllergies: (query = {}) => facade.getAllergies({
|
|
88
|
-
...state,
|
|
89
|
-
...query,
|
|
90
|
-
}),
|
|
91
|
-
getConditions: (query = {}) => facade.getConditions({
|
|
92
|
-
...state,
|
|
93
|
-
...query,
|
|
94
|
-
}),
|
|
95
|
-
getMedications: (query = {}) => facade.getMedications({
|
|
96
|
-
...state,
|
|
97
|
-
...query,
|
|
98
|
-
}),
|
|
99
|
-
getVitalSigns: (query = {}) => facade.getVitalSigns({
|
|
100
|
-
...state,
|
|
101
|
-
...query,
|
|
102
|
-
}),
|
|
103
|
-
getSectionCounts: () => facade.getSectionCounts({ sections: state.sections }),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Builds one reusable high-level clinical response view over the bundle body.
|
|
108
|
-
*/
|
|
109
24
|
function buildProcessedClinicalBundleResponse(body) {
|
|
110
25
|
const bundle = unwrapBody(body);
|
|
111
26
|
const views = toClinicalResourceExpandedViews(bundle);
|
|
112
27
|
const summary = summarizeClinicalBundle(bundle);
|
|
113
|
-
const documentFacade = createFhirDocumentFacade(normalizeClinicalDocumentBundle(bundle));
|
|
114
|
-
const reader = createClinicalBundleQueryBuilder(documentFacade);
|
|
115
|
-
const sectionCounts = documentFacade.getSectionCounts();
|
|
116
|
-
const sectionSummary = documentFacade.getSectionSummary();
|
|
117
28
|
return {
|
|
118
29
|
totalErrors: 0,
|
|
119
30
|
totalSections: Object.keys(buildClinicalSectionCounts(views)).length,
|
|
120
31
|
totalResources: summary.totalEntries,
|
|
121
32
|
totalResourcesInSection: buildClinicalSectionCounts(views),
|
|
33
|
+
totalNarratives: summary.xhtmlEntries,
|
|
34
|
+
totalNotes: summary.notedEntries,
|
|
122
35
|
summary,
|
|
123
36
|
views,
|
|
124
|
-
sectionCounts,
|
|
125
|
-
sectionSummary,
|
|
126
|
-
getSections: () => documentFacade.getSections(),
|
|
127
|
-
getEntries: (input) => documentFacade.getEntries(input),
|
|
128
|
-
getResources: (query) => documentFacade.getResources(query),
|
|
129
|
-
getByDates: (query, start, end) => documentFacade.getByDates(query, start, end),
|
|
130
|
-
getSectionCounts: (input) => documentFacade.getSectionCounts(input),
|
|
131
|
-
getSectionSummary: (input) => documentFacade.getSectionSummary(input),
|
|
132
|
-
getLocalTextAndIntDisplay: (resourceOrEntry) => documentFacade.getLocalTextAndIntDisplay(resourceOrEntry),
|
|
133
|
-
getXhtmlOrDerived: (resourceOrEntry) => documentFacade.getXhtmlOrDerived(resourceOrEntry),
|
|
134
|
-
getNarrative: (resourceOrEntry) => documentFacade.getNarrative(resourceOrEntry),
|
|
135
|
-
getAllergies: (query = {}) => documentFacade.getAllergies(query),
|
|
136
|
-
getConditions: (query = {}) => documentFacade.getConditions(query),
|
|
137
|
-
getMedications: (query = {}) => documentFacade.getMedications(query),
|
|
138
|
-
getVitalSigns: (query = {}) => documentFacade.getVitalSigns(query),
|
|
139
|
-
reader,
|
|
140
37
|
};
|
|
141
38
|
}
|
|
142
39
|
class ProfessionalSubjectIpsWorkspace {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdc-sdk-node-ts",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "Next-generation Node runtime package for the GDC SDK family",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Antifraud Services Inc.",
|
|
@@ -25,14 +25,15 @@
|
|
|
25
25
|
"test:e2e:live-gw:legacy-fhir": "npm run build && RUN_LIVE_GW_E2E=1 LIVE_GW_E2E_TRANSPORT=legacy-fhir node --test tests/live-gw-node-runtime.e2e.test.mjs",
|
|
26
26
|
"test:e2e:live-gw:all": "npm run build && RUN_LIVE_GW_E2E=1 LIVE_GW_E2E_TRANSPORT=all node --test tests/live-gw-node-runtime.e2e.test.mjs",
|
|
27
27
|
"test:e2e:live-gw:host-transaction:clean": "bash ./scripts/run-live-gw-host-transaction-clean.sh",
|
|
28
|
+
"test:e2e:live-gw:issue-recovery": "npm run build && node ./scripts/run-live-organization-issue-recovery.mjs",
|
|
28
29
|
"test:e2e:live-profile-runtime:individual": "npm run build && RUN_LIVE_PROFILE_RUNTIME_E2E=1 node --test tests/live-profile-runtime-individual.e2e.test.mjs",
|
|
29
30
|
"test:e2e:live-profile-runtime:professional": "npm run build && RUN_LIVE_PROFILE_RUNTIME_PROFESSIONAL_E2E=1 node --test tests/live-profile-runtime-professional.e2e.test.mjs",
|
|
30
31
|
"test:e2e:live-dialogue:consent-professional": "npm run build && RUN_LIVE_DIALOGUE_CONSENT_PROFESSIONAL_E2E=1 node --test tests/live-dialogue-consent-professional-access.e2e.test.mjs",
|
|
31
32
|
"test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
|
-
"gdc-common-utils-ts": "^2.0.
|
|
35
|
-
"gdc-sdk-core-ts": "^2.0.
|
|
35
|
+
"gdc-common-utils-ts": "^2.0.11",
|
|
36
|
+
"gdc-sdk-core-ts": "^2.0.8"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/node": "^20.14.10",
|