gdc-sdk-node-ts 2.9.3 → 2.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # gdc-sdk-node-ts
2
2
 
3
+ Development and releases follow the mandatory
4
+ [`local-first TDD and release contract`](docs/LOCAL_FIRST_RELEASE_CONTRACT.md).
5
+
3
6
  See [ARCHITECTURE.md](./ARCHITECTURE.md) and
4
7
  [CONTRIBUTING.md](./CONTRIBUTING.md) before adding node runtime facades,
5
8
  execution adapters, or orchestration tests.
@@ -69,50 +72,53 @@ If you are integrating this package for the first time, open these in order:
69
72
  2. [docs/101-SDK_END_TO_END.md](./docs/101-SDK_END_TO_END.md)
70
73
  Ordered onboarding guide with end-to-end journeys, copy/paste snippets, and
71
74
  the recommended reading path for new backend integrators.
72
- 3. [docs/101-HIGH_LEVEL_CLINICAL_PROFILE_WRITES.md](./docs/101-HIGH_LEVEL_CLINICAL_PROFILE_WRITES.md)
75
+ 3. [docs/101-PDQM_PATIENT_MATCH.md](./docs/101-PDQM_PATIENT_MATCH.md)
76
+ Resolve only `indexProviderDid` in Fabric, then use the high-level Node SDK
77
+ to call IHE PDQm `POST Patient/$match` with one FHIR `Parameters` request.
78
+ 4. [docs/101-HIGH_LEVEL_CLINICAL_PROFILE_WRITES.md](./docs/101-HIGH_LEVEL_CLINICAL_PROFILE_WRITES.md)
73
79
  Focused subset of the end-to-end guide: load a professional or individual
74
80
  member/controller profile, create or import clinical data in the selected
75
81
  index provider, and verify it through an authoritative summary readback.
76
- 4. [docs/101-PROFESSIONAL-CONSENT-SMART.md](./docs/101-PROFESSIONAL-CONSENT-SMART.md)
82
+ 5. [docs/101-PROFESSIONAL-CONSENT-SMART.md](./docs/101-PROFESSIONAL-CONSENT-SMART.md)
77
83
  Canonical professional DID, consent, VP and SMART flow without literal
78
84
  sections or caller-built audience URLs.
79
- 5. [docs/101-AUTHORIZED_SUBJECT_DIRECTORY.md](./docs/101-AUTHORIZED_SUBJECT_DIRECTORY.md)
85
+ 6. [docs/101-AUTHORIZED_SUBJECT_DIRECTORY.md](./docs/101-AUTHORIZED_SUBJECT_DIRECTORY.md)
80
86
  Signed OpenID account discovery of already-authorized subjects without
81
87
  treating the account token as VP, SMART or wallet proof.
82
- 6. [docs/101-SDK_INTEGRATION.md](./docs/101-SDK_INTEGRATION.md)
88
+ 7. [docs/101-SDK_INTEGRATION.md](./docs/101-SDK_INTEGRATION.md)
83
89
  Real backend setup plus the public runtime entrypoints:
84
90
  `HostOnboardingSdk`, `OrganizationControllerSdk`,
85
91
  `IndividualControllerSdk`, `ProfessionalSdk`, route-context usage, and the
86
92
  canonical `ProfileRuntime -> loadProfile(...) -> workspace/session -> actor facade -> submit/poll` shape.
87
- 7. [tests/101-live-full-cycle-bff-runtime.e2e.test.mjs](./tests/101-live-full-cycle-bff-runtime.e2e.test.mjs)
93
+ 8. [tests/101-live-full-cycle-bff-runtime.e2e.test.mjs](./tests/101-live-full-cycle-bff-runtime.e2e.test.mjs)
88
94
  Canonical live backend/BFF walkthrough on a fresh local GW lifecycle:
89
95
  host/tenant activation, employee provisioning, individual bootstrap,
90
96
  consent grant, professional SMART token, clinical read, and final cleanup.
91
- 8. [docs/101-LIVE_GW_LOCAL.md](./docs/101-LIVE_GW_LOCAL.md)
97
+ 9. [docs/101-LIVE_GW_LOCAL.md](./docs/101-LIVE_GW_LOCAL.md)
92
98
  Exact TTY/local/Docker commands for running the SDK against a real local GW
93
99
  CORE, including tenant bootstrap and employee-seat setup.
94
- 9. [docs/101-DISCOVERY.md](./docs/101-DISCOVERY.md)
100
+ 10. [docs/101-DISCOVERY.md](./docs/101-DISCOVERY.md)
95
101
  Node/BFF dataspace discovery, hosting-operator resolution, provider
96
102
  resolution, and the correct integration boundary for fallback and cache.
97
- 10. [gdc-sdk-core-ts/docs/101-SDK_FLOWS.md](https://github.com/Global-DataCare/gdc-sdk-core-ts/blob/main/docs/101-SDK_FLOWS.md)
103
+ 11. [gdc-sdk-core-ts/docs/101-SDK_FLOWS.md](https://github.com/Global-DataCare/gdc-sdk-core-ts/blob/main/docs/101-SDK_FLOWS.md)
98
104
  Actor split and business-flow map across organization, individual,
99
105
  permissions, invitation, import, and SMART flows.
100
- 11. [gwtemplate-node-ts/docs/PORTAL_API_TO_GW_CORE.md](https://github.com/Global-DataCare/gwtemplate-node-ts/blob/main/docs/PORTAL_API_TO_GW_CORE.md)
106
+ 12. [gwtemplate-node-ts/docs/PORTAL_API_TO_GW_CORE.md](https://github.com/Global-DataCare/gwtemplate-node-ts/blob/main/docs/PORTAL_API_TO_GW_CORE.md)
101
107
  Canonical portal/BFF functional map over GW CORE, including the domain
102
108
  split between `employees`, `related persons`, `members`, and `consents`.
103
- 12. [gdc-common-utils-ts/src/examples/](https://github.com/Global-DataCare/gdc-common-utils-ts/tree/main/src/examples)
109
+ 13. [gdc-common-utils-ts/src/examples/](https://github.com/Global-DataCare/gdc-common-utils-ts/tree/main/src/examples)
104
110
  Shared payload values used by the docs and tests.
105
- 13. [gdc-common-utils-ts/docs/101-LIFECYCLE.md](https://github.com/Global-DataCare/gdc-common-utils-ts/blob/main/docs/101-LIFECYCLE.md)
111
+ 14. [gdc-common-utils-ts/docs/101-LIFECYCLE.md](https://github.com/Global-DataCare/gdc-common-utils-ts/blob/main/docs/101-LIFECYCLE.md)
106
112
  Canonical `enable/disable/delete` semantics and copy/paste placeholders.
107
- 14. [tests/101-backend-profile-runtime.test.mjs](./tests/101-backend-profile-runtime.test.mjs)
113
+ 15. [tests/101-backend-profile-runtime.test.mjs](./tests/101-backend-profile-runtime.test.mjs)
108
114
  Technical runtime slice for profile/device/session orchestration internals.
109
115
  Read this after the public actor SDK guides, not before them.
110
- 15. [tests/101-individual-controller-backend-runtime.test.mjs](./tests/101-individual-controller-backend-runtime.test.mjs)
116
+ 16. [tests/101-individual-controller-backend-runtime.test.mjs](./tests/101-individual-controller-backend-runtime.test.mjs)
111
117
  Technical wrapper slice around the generic profile runtime. This is not the
112
118
  main onboarding path for new integrators.
113
- 16. [docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md](./docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md)
119
+ 17. [docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md](./docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md)
114
120
  Historical reconciliation note for the current CORE registration baseline.
115
- 17. [docs/NEXT_STEPS.md](./docs/NEXT_STEPS.md)
121
+ 18. [docs/NEXT_STEPS.md](./docs/NEXT_STEPS.md)
116
122
  Follow-up scope after GW CORE live validation, including the future user job
117
123
  manager boundary.
118
124
 
package/dist/index.d.ts CHANGED
@@ -51,3 +51,4 @@ export * from './orchestration/professional-sdk.js';
51
51
  export * from './orchestration/digital-twin-sdk.js';
52
52
  export * from './legacy-compat.js';
53
53
  export * from './local-terminology-bff.js';
54
+ export * from './pdqm-patient-match.js';
package/dist/index.js CHANGED
@@ -52,3 +52,4 @@ export * from './orchestration/professional-sdk.js';
52
52
  export * from './orchestration/digital-twin-sdk.js';
53
53
  export * from './legacy-compat.js';
54
54
  export * from './local-terminology-bff.js';
55
+ export * from './pdqm-patient-match.js';
@@ -22,6 +22,7 @@ import { type FhirR5SubscriptionBatchInput } from './fhir-r5-subscription-runtim
22
22
  import type { FhirR5SubscriptionTopic } from 'gdc-common-utils-ts/models/fhir-r5-subscription';
23
23
  import { type DigitalTwinMaterializationInput, type DigitalTwinSearchInput, type DigitalTwinSelectionInput } from './digital-twin.js';
24
24
  import { type AuthorizedIndividualSubject, type AuthorizedIndividualSubjectDirectoryInput } from './authorized-subject-directory.js';
25
+ import { type FhirPatientMatchBundle, type MatchPatientAtIndexProviderInput } from './pdqm-patient-match.js';
25
26
  export type HttpRuntimeClientOptions = {
26
27
  baseUrl: string;
27
28
  bearerToken?: string;
@@ -125,6 +126,15 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
125
126
  * Returns the configured ICA-issued runtime/software proof token, when present.
126
127
  */
127
128
  getRuntimeVpToken(): string | undefined;
129
+ /**
130
+ * Matches a known human identifier at the index provider resolved in Fabric.
131
+ *
132
+ * The BFF supplies the provider DID and its discovered FHIR base URL. This
133
+ * method never forwards the Fabric lookup hash. It sends one IHE PDQm
134
+ * `Parameters` request and returns the resulting FHIR search `Bundle`, while
135
+ * applying the runtime's configured FHIR, DIDComm plain or strict profile.
136
+ */
137
+ matchPatientAtIndexProvider(input: MatchPatientAtIndexProviderInput): Promise<FhirPatientMatchBundle>;
128
138
  /**
129
139
  * Builds a canonical GDC v1 resource/action path from a route context.
130
140
  */
@@ -20,6 +20,7 @@ import { runtimeUuid, wrapBundleAsGatewayTransactionMessage } from './runtime-me
20
20
  import { submitFhirR5SubscriptionBatchWithDeps, submitFhirR5SubscriptionTopicBatchWithDeps, } from './fhir-r5-subscription-runtime.js';
21
21
  import { materializeDigitalTwinWithDeps, saveDigitalTwinSelectionWithDeps, searchDigitalTwinsWithDeps, } from './digital-twin.js';
22
22
  import { listAuthorizedIndividualSubjectsWithDeps, } from './authorized-subject-directory.js';
23
+ import { matchPatientAtIndexProviderWithDeps, } from './pdqm-patient-match.js';
23
24
  const bootstrapFacade = createBootstrapFacade();
24
25
  /**
25
26
  * Runtime-oriented HTTP client for Node backends, BFFs, and workers that need
@@ -93,6 +94,22 @@ export class HttpRuntimeClient {
93
94
  getRuntimeVpToken() {
94
95
  return this.runtimeVpToken;
95
96
  }
97
+ /**
98
+ * Matches a known human identifier at the index provider resolved in Fabric.
99
+ *
100
+ * The BFF supplies the provider DID and its discovered FHIR base URL. This
101
+ * method never forwards the Fabric lookup hash. It sends one IHE PDQm
102
+ * `Parameters` request and returns the resulting FHIR search `Bundle`, while
103
+ * applying the runtime's configured FHIR, DIDComm plain or strict profile.
104
+ */
105
+ async matchPatientAtIndexProvider(input) {
106
+ return matchPatientAtIndexProviderWithDeps(input, {
107
+ transportProfile: this.transportProfile,
108
+ secureTransportAdapter: this.secureTransportAdapter,
109
+ createUuid: runtimeUuid,
110
+ post: async (url, rendered) => postRenderedWithRuntimeConfig(this.transportConfig, url, rendered),
111
+ });
112
+ }
96
113
  /**
97
114
  * Builds a canonical GDC v1 resource/action path from a route context.
98
115
  */
@@ -0,0 +1,44 @@
1
+ import { type FhirPatientMatchInput, type SecureDidcommTransportAdapter, type TransportProfile } from 'gdc-sdk-core-ts';
2
+ export type MatchPatientAtIndexProviderInput = Readonly<{
3
+ /** Provider FHIR base discovered from the resolved index-provider DID. */
4
+ fhirBaseUrl: string;
5
+ /** Patient containing the governed identifier known by the requesting BFF. */
6
+ patient: FhirPatientMatchInput;
7
+ /** DID of the authenticated professional, member or controller making the request. */
8
+ requesterDid: string;
9
+ /** Provider DID returned by the public subject-identifier ledger lookup. */
10
+ indexProviderDid: string;
11
+ /** Optional PDQm control that excludes possible, lower-confidence matches. */
12
+ onlyCertainMatches?: boolean;
13
+ }>;
14
+ export type FhirPatientMatchBundle = Readonly<{
15
+ resourceType: 'Bundle';
16
+ type: 'searchset';
17
+ [key: string]: unknown;
18
+ }>;
19
+ type PatientMatchDependencies = Readonly<{
20
+ transportProfile: TransportProfile;
21
+ secureTransportAdapter?: SecureDidcommTransportAdapter;
22
+ createUuid: () => string;
23
+ post: (url: string, request: Readonly<{
24
+ contentType: string;
25
+ accept: string;
26
+ body: Record<string, unknown> | string;
27
+ }>) => Promise<Readonly<{
28
+ status: number;
29
+ body: unknown;
30
+ }>>;
31
+ }>;
32
+ /**
33
+ * Calls the resolved provider's IHE PDQm `POST Patient/$match` facade.
34
+ *
35
+ * The opaque subject-identifier hash is deliberately absent: it stops at the
36
+ * preceding Fabric lookup. Native FHIR sends one `Parameters` body. DIDComm
37
+ * plain places that same resource in the only `body.data[]` entry. Strict mode
38
+ * signs and encrypts the identical DIDComm message through the wallet adapter
39
+ * and sends `request=<JWE>` as `application/x-www-form-urlencoded`.
40
+ *
41
+ * @see https://profiles.ihe.net/ITI/PDQm/ITI-119.html
42
+ */
43
+ export declare function matchPatientAtIndexProviderWithDeps(input: MatchPatientAtIndexProviderInput, dependencies: PatientMatchDependencies): Promise<FhirPatientMatchBundle>;
44
+ export {};
@@ -0,0 +1,63 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ import { buildPdqmPatientMatchGatewayBody, buildPdqmPatientMatchRequest, decodeTransportResponse, renderGatewayMessageRequest, TransportProfiles, } from 'gdc-sdk-core-ts';
3
+ function requiredDid(value, name) {
4
+ const normalized = String(value || '').trim();
5
+ if (!normalized.startsWith('did:'))
6
+ throw new TypeError(`${name} must be a DID.`);
7
+ return normalized;
8
+ }
9
+ function readPatientMatchBundle(value) {
10
+ const candidate = value && typeof value === 'object' && !Array.isArray(value)
11
+ && 'body' in value
12
+ ? value.body
13
+ : value;
14
+ if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
15
+ throw new Error('PDQm Patient/$match response must contain one FHIR search Bundle.');
16
+ }
17
+ const bundle = candidate;
18
+ if (bundle.resourceType !== 'Bundle' || bundle.type !== 'searchset') {
19
+ throw new Error('PDQm Patient/$match response must contain one FHIR search Bundle.');
20
+ }
21
+ return bundle;
22
+ }
23
+ /**
24
+ * Calls the resolved provider's IHE PDQm `POST Patient/$match` facade.
25
+ *
26
+ * The opaque subject-identifier hash is deliberately absent: it stops at the
27
+ * preceding Fabric lookup. Native FHIR sends one `Parameters` body. DIDComm
28
+ * plain places that same resource in the only `body.data[]` entry. Strict mode
29
+ * signs and encrypts the identical DIDComm message through the wallet adapter
30
+ * and sends `request=<JWE>` as `application/x-www-form-urlencoded`.
31
+ *
32
+ * @see https://profiles.ihe.net/ITI/PDQm/ITI-119.html
33
+ */
34
+ export async function matchPatientAtIndexProviderWithDeps(input, dependencies) {
35
+ const requesterDid = requiredDid(input.requesterDid, 'requesterDid');
36
+ const indexProviderDid = requiredDid(input.indexProviderDid, 'indexProviderDid');
37
+ const matchRequest = buildPdqmPatientMatchRequest({
38
+ fhirBaseUrl: input.fhirBaseUrl,
39
+ patient: input.patient,
40
+ onlyCertainMatches: input.onlyCertainMatches,
41
+ });
42
+ const thid = `pdqm-patient-match-${dependencies.createUuid()}`;
43
+ const rendered = dependencies.transportProfile === TransportProfiles.FhirJson
44
+ ? {
45
+ contentType: TransportProfiles.FhirJson,
46
+ accept: 'application/fhir+json, application/json',
47
+ body: matchRequest.body,
48
+ }
49
+ : await renderGatewayMessageRequest({
50
+ id: dependencies.createUuid(),
51
+ thid,
52
+ type: TransportProfiles.DidcommPlainJson,
53
+ from: requesterDid,
54
+ to: [indexProviderDid],
55
+ body: buildPdqmPatientMatchGatewayBody(matchRequest),
56
+ }, dependencies.transportProfile, dependencies.secureTransportAdapter);
57
+ const response = await dependencies.post(matchRequest.url, rendered);
58
+ if (response.status < 200 || response.status >= 300) {
59
+ throw new Error(`PDQm Patient/$match failed with HTTP ${response.status}.`);
60
+ }
61
+ const decoded = await decodeTransportResponse(response.body, dependencies.transportProfile, dependencies.secureTransportAdapter);
62
+ return readPatientMatchBundle(decoded);
63
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-sdk-node-ts",
3
- "version": "2.9.3",
3
+ "version": "2.9.5",
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.",
@@ -38,8 +38,8 @@
38
38
  "test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
39
39
  },
40
40
  "dependencies": {
41
- "gdc-common-utils-ts": "2.9.4",
42
- "gdc-sdk-core-ts": "2.9.2"
41
+ "gdc-common-utils-ts": "2.9.7",
42
+ "gdc-sdk-core-ts": "2.9.5"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^20.14.10",