gdc-sdk-node-ts 2.3.4 → 2.3.6

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
@@ -66,43 +66,46 @@ If you are integrating this package for the first time, open these in order:
66
66
  1. [gdc-sdk-core-ts/docs/101-SDK_PACKAGE_BOUNDARIES.md](https://github.com/Global-DataCare/gdc-sdk-core-ts/blob/main/docs/101-SDK_PACKAGE_BOUNDARIES.md)
67
67
  Why `core`, `node`, and `front` are separate packages, what belongs in each
68
68
  one, and why actor-scoped facades must stay aligned across runtimes.
69
- 1. [docs/101-SDK_END_TO_END.md](./docs/101-SDK_END_TO_END.md)
69
+ 2. [docs/101-SDK_END_TO_END.md](./docs/101-SDK_END_TO_END.md)
70
70
  Ordered onboarding guide with end-to-end journeys, copy/paste snippets, and
71
71
  the recommended reading path for new backend integrators.
72
- 2. [docs/101-SDK_INTEGRATION.md](./docs/101-SDK_INTEGRATION.md)
72
+ 3. [docs/101-PROFESSIONAL-CONSENT-SMART.md](./docs/101-PROFESSIONAL-CONSENT-SMART.md)
73
+ Canonical professional DID, consent, VP and SMART flow without literal
74
+ sections or caller-built audience URLs.
75
+ 4. [docs/101-SDK_INTEGRATION.md](./docs/101-SDK_INTEGRATION.md)
73
76
  Real backend setup plus the public runtime entrypoints:
74
77
  `HostOnboardingSdk`, `OrganizationControllerSdk`,
75
78
  `IndividualControllerSdk`, `ProfessionalSdk`, route-context usage, and the
76
79
  canonical `ProfileRuntime -> loadProfile(...) -> workspace/session -> actor facade -> submit/poll` shape.
77
- 3. [tests/101-live-full-cycle-bff-runtime.e2e.test.mjs](./tests/101-live-full-cycle-bff-runtime.e2e.test.mjs)
80
+ 5. [tests/101-live-full-cycle-bff-runtime.e2e.test.mjs](./tests/101-live-full-cycle-bff-runtime.e2e.test.mjs)
78
81
  Canonical live backend/BFF walkthrough on a fresh local GW lifecycle:
79
82
  host/tenant activation, employee provisioning, individual bootstrap,
80
83
  consent grant, professional SMART token, clinical read, and final cleanup.
81
- 4. [docs/101-LIVE_GW_LOCAL.md](./docs/101-LIVE_GW_LOCAL.md)
84
+ 6. [docs/101-LIVE_GW_LOCAL.md](./docs/101-LIVE_GW_LOCAL.md)
82
85
  Exact TTY/local/Docker commands for running the SDK against a real local GW
83
86
  CORE, including tenant bootstrap and employee-seat setup.
84
- 5. [docs/101-DISCOVERY.md](./docs/101-DISCOVERY.md)
87
+ 7. [docs/101-DISCOVERY.md](./docs/101-DISCOVERY.md)
85
88
  Node/BFF dataspace discovery, hosting-operator resolution, provider
86
89
  resolution, and the correct integration boundary for fallback and cache.
87
- 6. [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)
90
+ 8. [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)
88
91
  Actor split and business-flow map across organization, individual,
89
92
  permissions, invitation, import, and SMART flows.
90
- 7. [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)
93
+ 9. [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)
91
94
  Canonical portal/BFF functional map over GW CORE, including the domain
92
95
  split between `employees`, `related persons`, `members`, and `consents`.
93
- 8. [gdc-common-utils-ts/src/examples/](https://github.com/Global-DataCare/gdc-common-utils-ts/tree/main/src/examples)
96
+ 10. [gdc-common-utils-ts/src/examples/](https://github.com/Global-DataCare/gdc-common-utils-ts/tree/main/src/examples)
94
97
  Shared payload values used by the docs and tests.
95
- 9. [gdc-common-utils-ts/docs/101-LIFECYCLE.md](https://github.com/Global-DataCare/gdc-common-utils-ts/blob/main/docs/101-LIFECYCLE.md)
98
+ 11. [gdc-common-utils-ts/docs/101-LIFECYCLE.md](https://github.com/Global-DataCare/gdc-common-utils-ts/blob/main/docs/101-LIFECYCLE.md)
96
99
  Canonical `enable/disable/delete` semantics and copy/paste placeholders.
97
- 10. [tests/101-backend-profile-runtime.test.mjs](./tests/101-backend-profile-runtime.test.mjs)
100
+ 12. [tests/101-backend-profile-runtime.test.mjs](./tests/101-backend-profile-runtime.test.mjs)
98
101
  Technical runtime slice for profile/device/session orchestration internals.
99
102
  Read this after the public actor SDK guides, not before them.
100
- 11. [tests/101-individual-controller-backend-runtime.test.mjs](./tests/101-individual-controller-backend-runtime.test.mjs)
103
+ 13. [tests/101-individual-controller-backend-runtime.test.mjs](./tests/101-individual-controller-backend-runtime.test.mjs)
101
104
  Technical wrapper slice around the generic profile runtime. This is not the
102
105
  main onboarding path for new integrators.
103
- 12. [docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md](./docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md)
106
+ 14. [docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md](./docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md)
104
107
  Historical reconciliation note for the current CORE registration baseline.
105
- 13. [docs/NEXT_STEPS.md](./docs/NEXT_STEPS.md)
108
+ 15. [docs/NEXT_STEPS.md](./docs/NEXT_STEPS.md)
106
109
  Follow-up scope after GW CORE live validation, including the future user job
107
110
  manager boundary.
108
111
 
@@ -647,6 +650,10 @@ modules below.
647
650
  - [`NodeHttpClient.ingestCommunicationAndUpdateIndex(...)`](src/node-runtime-client.ts)
648
651
  - [`NodeHttpClient.submitCommunicationAndPoll(...)`](src/node-runtime-client.ts)
649
652
  - [`NodeHttpClient.searchClinicalBundle(...)`](src/node-runtime-client.ts)
653
+ - [`NodeHttpClient.updateClinicalSection(...)`](src/node-runtime-client.ts) for
654
+ one explicit section carried by a batch/collection Communication
655
+ - [`NodeHttpClient.updateClinicalSummary(...)`](src/node-runtime-client.ts) for
656
+ a Composition-first multi-section document
650
657
  - [`NodeHttpClient.searchLatestIps(...)`](src/node-runtime-client.ts)
651
658
  - [`NodeHttpClient.grantProfessionalAccess(...)`](src/node-runtime-client.ts)
652
659
  - [`NodeHttpClient.requestSmartToken(...)`](src/node-runtime-client.ts)
@@ -11,7 +11,7 @@ import { type SmartTokenRequestInput } from './smart-token.js';
11
11
  import { type EmployeeDeviceActivationRequestInput, type EmployeeDeviceActivationResult } from './device-activation.js';
12
12
  import { type OrganizationLicenseOrderConfirmInput } from './organization-license-order.js';
13
13
  import { type IndividualOrganizationBootstrapInput, type IndividualOrganizationStartResult } from './individual-start.js';
14
- import { type CommunicationIngestionInput, type BlockchainArtifactRegistrationInput, type VitalSignBatchCommunicationFromSearchResponseInput, type CommunicationParticipantRuntimeSearchInput, type ClinicalBundleSearchInput, type ClinicalSummaryReadResult, type ClinicalSummaryRequestInput, type GrantProfessionalAccessInput, type GrantProfessionalAccessResult, type IndividualMemberLifecycleInput, type IndividualMemberLicenseAddInput, type IndividualMemberLicenseInvitationInput, type IndividualMemberLicenseTransitionInput, type LicenseListRuntimeSearchInput, type LicenseOfferRuntimeSearchInput, type LicenseOrderRuntimeSearchInput, type OrganizationEmployeeCreationInput, type OrganizationEmployeeLifecycleInput, type OrganizationEmployeeSearchInput, type RevokeProfessionalAccessInput, type RevokeProfessionalAccessResult, type RelatedPersonUpsertInput } from './resource-operations.js';
14
+ import { type CommunicationIngestionInput, type BlockchainArtifactRegistrationInput, type VitalSignBatchCommunicationFromSearchResponseInput, type CommunicationParticipantRuntimeSearchInput, type ClinicalBundleSearchInput, type ClinicalSectionUpdateInput, type ClinicalSummaryReadResult, type ClinicalSummaryRequestInput, type ClinicalSummaryUpdateInput, type GrantProfessionalAccessInput, type GrantProfessionalAccessResult, type IndividualMemberLifecycleInput, type IndividualMemberLicenseAddInput, type IndividualMemberLicenseInvitationInput, type IndividualMemberLicenseTransitionInput, type LicenseListRuntimeSearchInput, type LicenseOfferRuntimeSearchInput, type LicenseOrderRuntimeSearchInput, type OrganizationEmployeeCreationInput, type OrganizationEmployeeLifecycleInput, type OrganizationEmployeeSearchInput, type RevokeProfessionalAccessInput, type RevokeProfessionalAccessResult, type RelatedPersonUpsertInput } from './resource-operations.js';
15
15
  import type { LegalOrganizationOrderInput } from './host-onboarding.js';
16
16
  import type { SmartTokenExchangeResult } from './smart-token.js';
17
17
  import type { NodeRuntimeClient, PollOptions, PollResult, SubmitAndPollResult, SubmitPayload, SubmitResponse } from './orchestration/client-port.js';
@@ -57,6 +57,12 @@ export type HttpRuntimeClientOptions = {
57
57
  communicationFormatRenderers?: CommunicationClinicalFormatRenderers;
58
58
  /** Injectable fetch implementation for BFF adapters and deterministic tests. */
59
59
  fetchImpl?: typeof fetch;
60
+ /**
61
+ * Optional trusted provider-index/DID resolver for subject-scoped SMART
62
+ * requests. The runtime uses the resolved endpoint for transport and JWT
63
+ * audience; application-level callers do not need to pass `audience`.
64
+ */
65
+ smartTokenEndpointResolver?: (subjectDid: string) => Promise<string | undefined>;
60
66
  };
61
67
  /**
62
68
  * @deprecated Prefer `HttpRuntimeClientOptions`.
@@ -82,6 +88,7 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
82
88
  private readonly secureTransportAdapter?;
83
89
  private readonly communicationFormatRenderers;
84
90
  private readonly fetchImpl?;
91
+ private readonly smartTokenEndpointResolver?;
85
92
  private readonly httpTraceFile?;
86
93
  private readonly tokenCache;
87
94
  private readonly paths;
@@ -402,6 +409,22 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
402
409
  * @param input Communication payload plus route/format options.
403
410
  */
404
411
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
412
+ /**
413
+ * Updates exactly one clinical section.
414
+ *
415
+ * The attached payload must be a `Bundle.type=batch|collection`, and the
416
+ * exact section is carried on the outer Communication. This flow is suitable
417
+ * for vital-sign or other explicitly section-scoped updates; it does not
418
+ * replace a multi-section IPS document.
419
+ */
420
+ updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<SubmitAndPollResult>;
421
+ /**
422
+ * Updates several clinical sections as one Composition-first document.
423
+ *
424
+ * The attached payload must be `Bundle.type=document` with `Composition` in
425
+ * `entry[0]`; its `section[].entry[]` references delimit the updated data.
426
+ */
427
+ updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<SubmitAndPollResult>;
405
428
  /**
406
429
  * Reads the authoritative clinical document currently available for one
407
430
  * subject through an auditable `Communication` request to `Subject/$summary`.
@@ -12,7 +12,7 @@ import { activateEmployeeDeviceWithActivationCodeWithDeps, activateEmployeeDevic
12
12
  import { extractOfferIdFromResponseBody, extractOfferPreviewFromResponseBody, } from './order-offer-summary.js';
13
13
  import { confirmOrganizationLicenseOrderWithDeps } from './organization-license-order.js';
14
14
  import { startIndividualOrganizationWithDeps } from './individual-start.js';
15
- import { createOrganizationEmployeeWithDeps, disableIndividualMemberWithDeps, disableIndividualOrganizationWithDeps, disableOrganizationEmployeeWithDeps, listIndividualLicenseOffersWithDeps, listIndividualLicenseOrdersWithDeps, listIndividualLicensesWithDeps, addFreeIndividualMemberLicensesWithDeps, issueIndividualMemberLicenseWithDeps, transitionIndividualMemberLicenseWithDeps, listOrganizationLicenseOffersWithDeps, listOrganizationLicenseOrdersWithDeps, listOrganizationLicensesWithDeps, grantProfessionalAccessWithDeps, ingestCommunicationAndUpdateIndexWithDeps, buildVitalSignBatchCommunicationFromSearchResponse, registerBlockchainArtifactAndUpdateIndexWithDeps, requestClinicalSummaryWithDeps, revokeProfessionalAccessWithDeps, searchCommunicationParticipantsWithDeps, purgeIndividualMemberWithDeps, purgeIndividualOrganizationWithDeps, purgeOrganizationEmployeeWithDeps, searchIndividualLicensesWithDeps, searchIndividualLicenseOffersWithDeps, searchIndividualLicenseOrdersWithDeps, searchOrganizationLicensesWithDeps, searchOrganizationLicenseOffersWithDeps, searchOrganizationLicenseOrdersWithDeps, searchOrganizationEmployeesWithDeps, searchClinicalBundleWithDeps, searchLatestIpsWithDeps, upsertRelatedPersonAndPollWithDeps, normalizeCommunicationPathFormatSegment, } from './resource-operations.js';
15
+ import { createOrganizationEmployeeWithDeps, disableIndividualMemberWithDeps, disableIndividualOrganizationWithDeps, disableOrganizationEmployeeWithDeps, listIndividualLicenseOffersWithDeps, listIndividualLicenseOrdersWithDeps, listIndividualLicensesWithDeps, addFreeIndividualMemberLicensesWithDeps, issueIndividualMemberLicenseWithDeps, transitionIndividualMemberLicenseWithDeps, listOrganizationLicenseOffersWithDeps, listOrganizationLicenseOrdersWithDeps, listOrganizationLicensesWithDeps, grantProfessionalAccessWithDeps, buildClinicalSectionUpdateIngestion, buildClinicalSummaryUpdateIngestion, ingestCommunicationAndUpdateIndexWithDeps, buildVitalSignBatchCommunicationFromSearchResponse, registerBlockchainArtifactAndUpdateIndexWithDeps, requestClinicalSummaryWithDeps, revokeProfessionalAccessWithDeps, searchCommunicationParticipantsWithDeps, purgeIndividualMemberWithDeps, purgeIndividualOrganizationWithDeps, purgeOrganizationEmployeeWithDeps, searchIndividualLicensesWithDeps, searchIndividualLicenseOffersWithDeps, searchIndividualLicenseOrdersWithDeps, searchOrganizationLicensesWithDeps, searchOrganizationLicenseOffersWithDeps, searchOrganizationLicenseOrdersWithDeps, searchOrganizationEmployeesWithDeps, searchClinicalBundleWithDeps, searchLatestIpsWithDeps, upsertRelatedPersonAndPollWithDeps, normalizeCommunicationPathFormatSegment, } from './resource-operations.js';
16
16
  import { submitAndPollWithMethods } from './orchestration/client-port.js';
17
17
  import { buildRuntimeHeaders, fetchWithTimeout, parseResponseBody, pollBatchResponseWithRuntimeConfig, postJsonWithRuntimeConfig, postRenderedWithRuntimeConfig, } from './runtime-transport.js';
18
18
  import { activateOrganizationInGatewayFromIcaProofWithDeps, submitLegalOrganizationIssueWithDeps, submitLegalOrganizationVerificationTransactionWithDeps, submitOrganizationDidBindingWithDeps, } from './runtime-host-submission.js';
@@ -68,6 +68,7 @@ export class HttpRuntimeClient {
68
68
  this.secureTransportAdapter = options.secureTransportAdapter;
69
69
  this.communicationFormatRenderers = options.communicationFormatRenderers || {};
70
70
  this.fetchImpl = options.fetchImpl;
71
+ this.smartTokenEndpointResolver = options.smartTokenEndpointResolver;
71
72
  this.httpTraceFile = String(process.env.SDK_HTTP_TRACE_FILE || '').trim() || undefined;
72
73
  this.paths = new RuntimeClientPaths(this.ctx);
73
74
  }
@@ -690,6 +691,7 @@ export class HttpRuntimeClient {
690
691
  identityTokenExchangePollPath: this.paths.identityTokenExchangePollPath.bind(this.paths),
691
692
  identityOpenIdSmartTokenPath: this.paths.identityOpenIdSmartTokenPath.bind(this.paths),
692
693
  identityOpenIdSmartTokenPollPath: this.paths.identityOpenIdSmartTokenPollPath.bind(this.paths),
694
+ resolveSmartTokenEndpoint: this.smartTokenEndpointResolver,
693
695
  submitAndPoll: this.submitAndPoll.bind(this),
694
696
  setTokenCache: (tokenCacheKey, token) => this.tokenCache.set(tokenCacheKey, token),
695
697
  });
@@ -743,6 +745,26 @@ export class HttpRuntimeClient {
743
745
  submitAndPoll: this.submitAndPoll.bind(this),
744
746
  });
745
747
  }
748
+ /**
749
+ * Updates exactly one clinical section.
750
+ *
751
+ * The attached payload must be a `Bundle.type=batch|collection`, and the
752
+ * exact section is carried on the outer Communication. This flow is suitable
753
+ * for vital-sign or other explicitly section-scoped updates; it does not
754
+ * replace a multi-section IPS document.
755
+ */
756
+ async updateClinicalSection(ctx, input) {
757
+ return this.ingestCommunicationAndUpdateIndex(ctx, buildClinicalSectionUpdateIngestion(input));
758
+ }
759
+ /**
760
+ * Updates several clinical sections as one Composition-first document.
761
+ *
762
+ * The attached payload must be `Bundle.type=document` with `Composition` in
763
+ * `entry[0]`; its `section[].entry[]` references delimit the updated data.
764
+ */
765
+ async updateClinicalSummary(ctx, input) {
766
+ return this.ingestCommunicationAndUpdateIndex(ctx, buildClinicalSummaryUpdateIngestion(input));
767
+ }
746
768
  /**
747
769
  * Reads the authoritative clinical document currently available for one
748
770
  * subject through an auditable `Communication` request to `Subject/$summary`.
@@ -13,7 +13,7 @@ import type { FamilyOrganizationSearchInput } from '../family-organization-searc
13
13
  import type { EnsureFamilyOrganizationRegistrationInput, EnsureFamilyOrganizationRegistrationResult } from '../family-organization-registration.js';
14
14
  import type { OrganizationLicenseOrderConfirmInput } from '../organization-license-order.js';
15
15
  import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
16
- import type { CommunicationIngestionInput, BlockchainArtifactRegistrationInput, CommunicationParticipantRuntimeSearchInput, ClinicalBundleSearchInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, VitalSignBatchCommunicationFromSearchResponseInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IndividualMemberLifecycleInput, IndividualMemberLicenseAddInput, IndividualMemberLicenseInvitationInput, IndividualMemberLicenseTransitionInput, IpsOrFhirImportInput, OrganizationEmployeeCreationInput, OrganizationEmployeeLifecycleInput, OrganizationEmployeeSearchInput, RevokeProfessionalAccessInput, RevokeProfessionalAccessResult, RelatedPersonUpsertInput } from '../resource-operations.js';
16
+ import type { CommunicationIngestionInput, BlockchainArtifactRegistrationInput, CommunicationParticipantRuntimeSearchInput, ClinicalBundleSearchInput, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, VitalSignBatchCommunicationFromSearchResponseInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IndividualMemberLifecycleInput, IndividualMemberLicenseAddInput, IndividualMemberLicenseInvitationInput, IndividualMemberLicenseTransitionInput, IpsOrFhirImportInput, OrganizationEmployeeCreationInput, OrganizationEmployeeLifecycleInput, OrganizationEmployeeSearchInput, RevokeProfessionalAccessInput, RevokeProfessionalAccessResult, RelatedPersonUpsertInput } from '../resource-operations.js';
17
17
  /**
18
18
  * Shared node-runtime activation input.
19
19
  *
@@ -89,6 +89,8 @@ export type RuntimeClient = {
89
89
  disableIndividualOrganization?: (ctx: RouteContext, input: IndividualOrganizationLifecycleInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
90
90
  purgeIndividualOrganization?: (ctx: RouteContext, input: IndividualOrganizationLifecycleInput, pollOptions?: PollOptions) => Promise<SubmitAndPollResult>;
91
91
  ingestCommunicationAndUpdateIndex?: (ctx: RouteContext, input: CommunicationIngestionInput) => Promise<SubmitAndPollResult>;
92
+ updateClinicalSection?: (ctx: RouteContext, input: ClinicalSectionUpdateInput) => Promise<SubmitAndPollResult>;
93
+ updateClinicalSummary?: (ctx: RouteContext, input: ClinicalSummaryUpdateInput) => Promise<SubmitAndPollResult>;
92
94
  requestClinicalSummary?: (ctx: RouteContext, input: ClinicalSummaryRequestInput) => Promise<ClinicalSummaryReadResult>;
93
95
  registerBlockchainArtifactAndUpdateIndex?: (ctx: RouteContext, input: BlockchainArtifactRegistrationInput) => Promise<SubmitAndPollResult>;
94
96
  searchCommunicationParticipants?: (ctx: RouteContext, input: CommunicationParticipantRuntimeSearchInput) => Promise<SubmitAndPollResult>;
@@ -7,7 +7,7 @@ import type { IndividualOrganizationConfirmOrderInput, RouteContext } from '../i
7
7
  import type { IndividualOrganizationBootstrapInput, IndividualOrganizationStartResult } from '../individual-start.js';
8
8
  import type { NodeCapability } from '../session.js';
9
9
  import type { IndividualOrganizationLifecycleInput } from 'gdc-sdk-core-ts';
10
- import type { BlockchainArtifactRegistrationInput, ClinicalBundleSearchInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IndividualMemberLifecycleInput, IndividualMemberLicenseAddInput, IndividualMemberLicenseInvitationInput, IndividualMemberLicenseTransitionInput, IpsOrFhirImportInput, LicenseListRuntimeSearchInput, LicenseOfferRuntimeSearchInput, LicenseOrderRuntimeSearchInput, RevokeProfessionalAccessInput, RevokeProfessionalAccessResult, RelatedPersonUpsertInput } from '../resource-operations.js';
10
+ import type { BlockchainArtifactRegistrationInput, ClinicalBundleSearchInput, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IndividualMemberLifecycleInput, IndividualMemberLicenseAddInput, IndividualMemberLicenseInvitationInput, IndividualMemberLicenseTransitionInput, IpsOrFhirImportInput, LicenseListRuntimeSearchInput, LicenseOfferRuntimeSearchInput, LicenseOrderRuntimeSearchInput, RevokeProfessionalAccessInput, RevokeProfessionalAccessResult, RelatedPersonUpsertInput } from '../resource-operations.js';
11
11
  import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
12
12
  /**
13
13
  * Individual-controller oriented facade over a `NodeRuntimeClient`.
@@ -90,6 +90,10 @@ export declare class IndividualControllerSdk {
90
90
  * Ingests a FHIR `Communication` and waits for indexing.
91
91
  */
92
92
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
93
+ /** Updates one exact clinical section through a section-scoped batch/collection. */
94
+ updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<SubmitAndPollResult>;
95
+ /** Updates the multi-section summary through a Composition-first document. */
96
+ updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<SubmitAndPollResult>;
93
97
  /**
94
98
  * Reads the subject's available clinical document through
95
99
  * `Communication -> Subject/$summary -> FHIR Parameters`.
@@ -128,6 +128,16 @@ export class IndividualControllerSdk {
128
128
  assertFacadeCapability(this.capabilities, ActorCapabilities.IndividualIngestCommunication, ActorKinds.IndividualController, 'ingestCommunicationAndUpdateIndex');
129
129
  return requireClientMethod(this.client, 'ingestCommunicationAndUpdateIndex')(ctx, input);
130
130
  }
131
+ /** Updates one exact clinical section through a section-scoped batch/collection. */
132
+ updateClinicalSection(ctx, input) {
133
+ assertFacadeCapability(this.capabilities, ActorCapabilities.IndividualIngestCommunication, ActorKinds.IndividualController, 'updateClinicalSection');
134
+ return requireClientMethod(this.client, 'updateClinicalSection')(ctx, input);
135
+ }
136
+ /** Updates the multi-section summary through a Composition-first document. */
137
+ updateClinicalSummary(ctx, input) {
138
+ assertFacadeCapability(this.capabilities, ActorCapabilities.IndividualIngestCommunication, ActorKinds.IndividualController, 'updateClinicalSummary');
139
+ return requireClientMethod(this.client, 'updateClinicalSummary')(ctx, input);
140
+ }
131
141
  /**
132
142
  * Reads the subject's available clinical document through
133
143
  * `Communication -> Subject/$summary -> FHIR Parameters`.
@@ -2,7 +2,7 @@ import { type IndividualMemberCredentialInput, type IndividualMemberVpPayloadInp
2
2
  import { type NodeRuntimeClient } from './client-port.js';
3
3
  import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
4
4
  import type { RouteContext } from '../individual-onboarding.js';
5
- import type { ClinicalBundleSearchInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, CommunicationIngestionInput, RelatedPersonUpsertInput } from '../resource-operations.js';
5
+ import type { ClinicalBundleSearchInput, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, CommunicationIngestionInput, RelatedPersonUpsertInput } from '../resource-operations.js';
6
6
  export declare class IndividualMemberSdk {
7
7
  private readonly client;
8
8
  constructor(client: NodeRuntimeClient);
@@ -23,6 +23,10 @@ export declare class IndividualMemberSdk {
23
23
  * SMART token and accepted RelatedPerson/Consent relationship.
24
24
  */
25
25
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<import("gdc-sdk-core-ts/polling-model.js").SubmitAndPollResult>;
26
+ /** Updates one authorized clinical section through a scoped batch/collection. */
27
+ updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<import("gdc-sdk-core-ts/polling-model.js").SubmitAndPollResult>;
28
+ /** Updates an authorized multi-section summary document. */
29
+ updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<import("gdc-sdk-core-ts/polling-model.js").SubmitAndPollResult>;
26
30
  /** Reads the member-authorized `$summary` document without mutating the subject index. */
27
31
  requestClinicalSummary(ctx: RouteContext, input: ClinicalSummaryRequestInput): Promise<ClinicalSummaryReadResult>;
28
32
  /** Reads subject-scoped clinical documents permitted to this member. */
@@ -28,6 +28,14 @@ export class IndividualMemberSdk {
28
28
  ingestCommunicationAndUpdateIndex(ctx, input) {
29
29
  return requireClientMethod(this.client, 'ingestCommunicationAndUpdateIndex')(ctx, input);
30
30
  }
31
+ /** Updates one authorized clinical section through a scoped batch/collection. */
32
+ updateClinicalSection(ctx, input) {
33
+ return requireClientMethod(this.client, 'updateClinicalSection')(ctx, input);
34
+ }
35
+ /** Updates an authorized multi-section summary document. */
36
+ updateClinicalSummary(ctx, input) {
37
+ return requireClientMethod(this.client, 'updateClinicalSummary')(ctx, input);
38
+ }
31
39
  /** Reads the member-authorized `$summary` document without mutating the subject index. */
32
40
  requestClinicalSummary(ctx, input) {
33
41
  return requireClientMethod(this.client, 'requestClinicalSummary')(ctx, input);
@@ -1,7 +1,7 @@
1
1
  import { type NodeRuntimeClient, type PollOptions, type SubmitAndPollResult, type SubmitPayload } from './client-port.js';
2
2
  import type { IndividualOrganizationBootstrapInput, IndividualOrganizationStartResult } from '../individual-start.js';
3
3
  import type { RouteContext } from '../individual-onboarding.js';
4
- import type { BlockchainArtifactRegistrationInput, ClinicalBundleSearchInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IpsOrFhirImportInput, LicenseListRuntimeSearchInput, LicenseOfferRuntimeSearchInput, LicenseOrderRuntimeSearchInput } from '../resource-operations.js';
4
+ import type { BlockchainArtifactRegistrationInput, ClinicalBundleSearchInput, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, DigitalTwinGenerationInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, IpsOrFhirImportInput, LicenseListRuntimeSearchInput, LicenseOfferRuntimeSearchInput, LicenseOrderRuntimeSearchInput } from '../resource-operations.js';
5
5
  import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
6
6
  export declare class PersonalSdk {
7
7
  private readonly client;
@@ -14,6 +14,10 @@ export declare class PersonalSdk {
14
14
  importIpsOrFhirAndUpdateIndex(ctx: RouteContext, input: IpsOrFhirImportInput): Promise<SubmitAndPollResult>;
15
15
  /** Ingests canonical Communication and waits for projection completion. */
16
16
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
17
+ /** Updates one exact clinical section through a section-scoped batch/collection. */
18
+ updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<SubmitAndPollResult>;
19
+ /** Updates the multi-section clinical summary through a Composition-first document. */
20
+ updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<SubmitAndPollResult>;
17
21
  /** Reads the current subject through Communication `$summary`; it performs no ingestion. */
18
22
  requestClinicalSummary(ctx: RouteContext, input: ClinicalSummaryRequestInput): Promise<ClinicalSummaryReadResult>;
19
23
  /** Registers one FHIR resource or raw artifact on blockchain before communication. */
@@ -20,6 +20,14 @@ export class PersonalSdk {
20
20
  ingestCommunicationAndUpdateIndex(ctx, input) {
21
21
  return requireClientMethod(this.client, 'ingestCommunicationAndUpdateIndex')(ctx, input);
22
22
  }
23
+ /** Updates one exact clinical section through a section-scoped batch/collection. */
24
+ updateClinicalSection(ctx, input) {
25
+ return requireClientMethod(this.client, 'updateClinicalSection')(ctx, input);
26
+ }
27
+ /** Updates the multi-section clinical summary through a Composition-first document. */
28
+ updateClinicalSummary(ctx, input) {
29
+ return requireClientMethod(this.client, 'updateClinicalSummary')(ctx, input);
30
+ }
23
31
  /** Reads the current subject through Communication `$summary`; it performs no ingestion. */
24
32
  requestClinicalSummary(ctx, input) {
25
33
  return requireClientMethod(this.client, 'requestClinicalSummary')(ctx, input);
@@ -2,7 +2,7 @@ import { type ProfessionalEmployeeCredentialInput, type ProfessionalSmartVpPaylo
2
2
  import { type NodeRuntimeClient, type PollOptions, type SubmitAndPollResult, type SubmitPayload } from './client-port.js';
3
3
  import type { RouteContext } from '../individual-onboarding.js';
4
4
  import type { SmartTokenExchangeResult, SmartTokenRequestInput } from '../smart-token.js';
5
- import type { BlockchainArtifactRegistrationInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, ClinicalBundleSearchInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, VitalSignBatchCommunicationFromSearchResponseInput } from '../resource-operations.js';
5
+ import type { BlockchainArtifactRegistrationInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, ClinicalBundleSearchInput, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, VitalSignBatchCommunicationFromSearchResponseInput } from '../resource-operations.js';
6
6
  /**
7
7
  * Professional-oriented facade for runtime actions that belong to the
8
8
  * professional actor itself after tenant and employee provisioning have already
@@ -26,6 +26,11 @@ export declare class ProfessionalSdk {
26
26
  * - `subjectDid`
27
27
  * - requested `scopes`
28
28
  *
29
+ * The actor DID must be the same identifier used by the consent grant and
30
+ * the professional VP. High-level callers omit `audience`; the runtime
31
+ * resolves the subject provider's SMART endpoint or uses the exact endpoint
32
+ * of its configured GW route.
33
+ *
29
34
  * Tenant route context can be inherited from the configured
30
35
  * `NodeHttpClient({ ctx })` instead of being repeated on every call.
31
36
  */
@@ -70,6 +75,10 @@ export declare class ProfessionalSdk {
70
75
  * Ingests a FHIR `Communication` and waits for indexing.
71
76
  */
72
77
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
78
+ /** Updates one consent-authorized clinical section through a scoped batch/collection. */
79
+ updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<SubmitAndPollResult>;
80
+ /** Updates a consent-authorized multi-section summary document. */
81
+ updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<SubmitAndPollResult>;
73
82
  /**
74
83
  * Registers one FHIR resource or raw document artifact on blockchain before
75
84
  * the artifact is attached to a Communication.
@@ -26,6 +26,11 @@ export class ProfessionalSdk {
26
26
  * - `subjectDid`
27
27
  * - requested `scopes`
28
28
  *
29
+ * The actor DID must be the same identifier used by the consent grant and
30
+ * the professional VP. High-level callers omit `audience`; the runtime
31
+ * resolves the subject provider's SMART endpoint or uses the exact endpoint
32
+ * of its configured GW route.
33
+ *
29
34
  * Tenant route context can be inherited from the configured
30
35
  * `NodeHttpClient({ ctx })` instead of being repeated on every call.
31
36
  */
@@ -84,6 +89,14 @@ export class ProfessionalSdk {
84
89
  ingestCommunicationAndUpdateIndex(ctx, input) {
85
90
  return requireClientMethod(this.client, 'ingestCommunicationAndUpdateIndex')(ctx, input);
86
91
  }
92
+ /** Updates one consent-authorized clinical section through a scoped batch/collection. */
93
+ updateClinicalSection(ctx, input) {
94
+ return requireClientMethod(this.client, 'updateClinicalSection')(ctx, input);
95
+ }
96
+ /** Updates a consent-authorized multi-section summary document. */
97
+ updateClinicalSummary(ctx, input) {
98
+ return requireClientMethod(this.client, 'updateClinicalSummary')(ctx, input);
99
+ }
87
100
  /**
88
101
  * Registers one FHIR resource or raw document artifact on blockchain before
89
102
  * the artifact is attached to a Communication.
@@ -1,5 +1,5 @@
1
1
  import type { DeviceAppType } from 'gdc-common-utils-ts/constants/device';
2
- import { type ClinicalSummaryReadResult, type ClinicalSummaryRequestInput } from 'gdc-sdk-core-ts';
2
+ import { type ClinicalSectionUpdateCommunicationInput, type ClinicalUpdateCommunicationInput, type ClinicalSummaryReadResult, type ClinicalSummaryRequestInput } from 'gdc-sdk-core-ts';
3
3
  import type { LicenseOfferSearchState, LicenseOrderSearchState } from 'gdc-common-utils-ts/utils/license-commercial-search';
4
4
  import type { LicenseListSearchState } from 'gdc-common-utils-ts/utils/license-list-search';
5
5
  import type { BundleSearchQuery, CommMsgExtendedCommunicationOutboxJob, CommunicationOutboxJob, CommunicationInput, DateRange, EmployeeSearchValue, IndividualOrganizationLifecycleInput, TransportProfile } from 'gdc-sdk-core-ts';
@@ -232,6 +232,20 @@ export type CommunicationIngestionInput = {
232
232
  intervalMs?: number;
233
233
  };
234
234
  };
235
+ type ClinicalUpdateRuntimeOptions = Readonly<{
236
+ transportProfile?: TransportProfile;
237
+ clinicalFormat?: string;
238
+ pollOptions?: {
239
+ timeoutMs?: number;
240
+ intervalMs?: number;
241
+ };
242
+ }>;
243
+ /** Updates exactly one clinical section through a scoped batch/collection. */
244
+ export type ClinicalSectionUpdateInput = ClinicalSectionUpdateCommunicationInput & ClinicalUpdateRuntimeOptions;
245
+ /** Updates one complete multi-section clinical summary document. */
246
+ export type ClinicalSummaryUpdateInput = ClinicalUpdateCommunicationInput & ClinicalUpdateRuntimeOptions;
247
+ export declare function buildClinicalSectionUpdateIngestion(input: ClinicalSectionUpdateInput): CommunicationIngestionInput;
248
+ export declare function buildClinicalSummaryUpdateIngestion(input: ClinicalSummaryUpdateInput): CommunicationIngestionInput;
235
249
  export type BlockchainArtifactRegistrationInput = {
236
250
  subject: string;
237
251
  resource?: Record<string, unknown>;
@@ -351,15 +365,19 @@ export type GrantProfessionalAccessInput = {
351
365
  /**
352
366
  * Canonical flat actor identifier for the actor receiving the permission.
353
367
  *
354
- * Preferred input forms:
355
- * - `did:web:...`
368
+ * Canonical professional grant input:
369
+ * - the exact `did:web:...:employee:<multibase>:<role>` actor DID reused by
370
+ * the employee profile, VP credential subject and SMART request
371
+ *
372
+ * Compatibility input forms:
356
373
  * - `user@example.org`
357
374
  * - `tel:+34600111222`
358
375
  * - `ES`
359
376
  * - comma-separated lists or string arrays of those tokens
360
377
  *
361
- * A legacy structured object is still accepted for compatibility, but new
362
- * integrations should send canonical strings or string arrays.
378
+ * Email/phone targets and legacy structured objects remain accepted for
379
+ * compatibility, but they do not automatically authorize a later SMART
380
+ * request made with a different derived professional DID.
363
381
  */
364
382
  actorId?: ConsentActorTargetInput;
365
383
  /**
@@ -3,9 +3,25 @@ import { HealthcareBasicSections, ResourceTypesFhirR4 } from 'gdc-common-utils-t
3
3
  import { Format } from 'gdc-common-utils-ts/constants/Schemas';
4
4
  import { RelatedPersonClaim } from 'gdc-common-utils-ts/models/interoperable-claims/related-person-claims';
5
5
  import { buildCommunicationParticipantSearchBundle, buildBlockchainArtifactDocumentReference, BundleQuery, createInteroperableResourceOperationEditor, IndividualOrganizationLifecycleEditor, LicenseOfferSearchEditor, LicenseOrderSearchEditor, InteroperableLifecycleStatuses, LicenseListSearchEditor, buildLicenseIssueEntry, buildLicensePurchaseEntry, } from 'gdc-common-utils-ts';
6
- import { addFhirResourceToCommunication, createCommunicationResource, buildClinicalSummaryCommunicationJob, readClinicalSummaryOperationResult, } from 'gdc-sdk-core-ts';
6
+ import { addFhirResourceToCommunication, createCommunicationResource, buildClinicalSummaryCommunicationJob, createClinicalSectionUpdateOutboxJob, createClinicalSummaryUpdateOutboxJob, readClinicalSummaryOperationResult, } from 'gdc-sdk-core-ts';
7
7
  import { GwCoreLifecycleRequestMethod, GwCoreLifecycleRequestType, GwCoreLifecycleTodo, } from './constants/lifecycle.js';
8
8
  import { buildEmployeeBatchEntry, buildEmployeeSearchBundle, ConsentClaims, } from 'gdc-sdk-core-ts';
9
+ export function buildClinicalSectionUpdateIngestion(input) {
10
+ return {
11
+ communicationJob: createClinicalSectionUpdateOutboxJob(input),
12
+ clinicalFormat: input.clinicalFormat,
13
+ transportProfile: input.transportProfile,
14
+ pollOptions: input.pollOptions,
15
+ };
16
+ }
17
+ export function buildClinicalSummaryUpdateIngestion(input) {
18
+ return {
19
+ communicationJob: createClinicalSummaryUpdateOutboxJob(input),
20
+ clinicalFormat: input.clinicalFormat,
21
+ transportProfile: input.transportProfile,
22
+ pollOptions: input.pollOptions,
23
+ };
24
+ }
9
25
  export async function createOrganizationEmployeeWithDeps(routeCtx, input, options, deps) {
10
26
  const payload = buildEmployeeLifecyclePayload({
11
27
  routeCtx,
@@ -2,6 +2,7 @@
2
2
  import { randomBytes } from 'node:crypto';
3
3
  import { NodeManagedWallet } from './node-managed-wallet.js';
4
4
  import { NodeHttpClient } from './node-runtime-client.js';
5
+ import { buildIdentityOpenIdSmartTokenPath } from './runtime-paths.js';
5
6
  import { ProfilePinRejectedError, openServerProfileSecret, protectServerProfileSecret, } from './server-profile-protection.js';
6
7
  /**
7
8
  * Coordinates device registration, two-factor profile protection and SMART sessions.
@@ -95,14 +96,18 @@ export class ServerProfileSessionManager {
95
96
  }
96
97
  profile = await this.ensureRequiredStorageProfile(profile, seed);
97
98
  const wallet = await this.createWallet(profile.profileId, seed);
98
- const assertion = await buildWalletClientAssertion(wallet, profile, this.options.gatewayBaseUrl, now);
99
+ const smartTokenEndpoint = [
100
+ this.options.gatewayBaseUrl.replace(/\/+$/, ''),
101
+ buildIdentityOpenIdSmartTokenPath(profile.routeContext),
102
+ ].join('');
103
+ const assertion = await buildWalletClientAssertion(wallet, profile, smartTokenEndpoint, now);
99
104
  const token = await this.createClient(profile.routeContext, input.idToken).requestSmartToken({
100
105
  ...profile.routeContext,
101
106
  actorDid: profile.actorDid,
102
107
  subjectDid: input.subjectDid,
103
108
  clientId: profile.clientId,
104
109
  issuer: profile.clientId,
105
- audience: this.options.gatewayBaseUrl,
110
+ audience: smartTokenEndpoint,
106
111
  idToken: input.idToken,
107
112
  vpToken,
108
113
  clientAssertion: assertion,
@@ -93,6 +93,13 @@ type RequestSmartTokenDeps = {
93
93
  identityTokenExchangePollPath: (ctx: RouteContext) => string;
94
94
  identityOpenIdSmartTokenPath: (ctx: RouteContext) => string;
95
95
  identityOpenIdSmartTokenPollPath: (ctx: RouteContext) => string;
96
+ /**
97
+ * Trusted runtime resolver for the provider that owns the subject.
98
+ *
99
+ * Product code may back this with an index/DID discovery adapter. The
100
+ * high-level caller does not receive or manage the resolver's cache.
101
+ */
102
+ resolveSmartTokenEndpoint?: (subjectDid: string) => Promise<string | undefined>;
96
103
  submitAndPoll: (submitPath: string, pollPath: string, payload: {
97
104
  thid?: string;
98
105
  } & Record<string, unknown>, options?: PollOptions) => Promise<SubmitAndPollResult>;
@@ -27,7 +27,19 @@ export async function requestSmartTokenWithDeps(deps) {
27
27
  if (deps.input.smartTokenKind === 'openid-smart') {
28
28
  const actorDid = String(deps.input.actorDid || '').trim() || undefined;
29
29
  const resolvedClientId = deps.input.clientId || actorDid || deps.input.subjectDid || deps.routeCtx.tenantId;
30
- const resolvedAudience = deps.input.audience || deps.routeCtx.tenantId;
30
+ const configuredSubmitPath = deps.identityOpenIdSmartTokenPath(deps.routeCtx);
31
+ const configuredPollPath = deps.identityOpenIdSmartTokenPollPath(deps.routeCtx);
32
+ const explicitAudience = String(deps.input.audience || '').trim();
33
+ const subjectDid = String(deps.input.subjectDid || '').trim();
34
+ const discoveredEndpoint = !explicitAudience && subjectDid && deps.resolveSmartTokenEndpoint
35
+ ? normalizeResolvedSmartTokenEndpoint(await deps.resolveSmartTokenEndpoint(subjectDid))
36
+ : undefined;
37
+ const configuredEndpoint = joinRuntimeUrl(deps.baseUrl, configuredSubmitPath);
38
+ const resolvedAudience = explicitAudience || discoveredEndpoint || configuredEndpoint;
39
+ const submitPath = discoveredEndpoint || configuredSubmitPath;
40
+ const pollPath = discoveredEndpoint
41
+ ? smartTokenPollEndpointFromTokenEndpoint(discoveredEndpoint)
42
+ : configuredPollPath;
31
43
  const clientAssertion = await resolveClientAssertion({
32
44
  clientAssertion: deps.input.clientAssertion,
33
45
  clientAssertionBuilder: deps.input.clientAssertionBuilder,
@@ -59,7 +71,7 @@ export async function requestSmartTokenWithDeps(deps) {
59
71
  },
60
72
  ...(deps.input.additionalClaims || {}),
61
73
  };
62
- const exchange = await deps.submitAndPoll(deps.identityOpenIdSmartTokenPath(deps.routeCtx), deps.identityOpenIdSmartTokenPollPath(deps.routeCtx), smartPayload, pollOptions);
74
+ const exchange = await deps.submitAndPoll(submitPath, pollPath, smartPayload, pollOptions);
63
75
  return resolveTokenExchangeResult(exchange, normalizedScopes, tokenCacheKey, deps.setTokenCache);
64
76
  }
65
77
  const payload = {
@@ -75,6 +87,33 @@ export async function requestSmartTokenWithDeps(deps) {
75
87
  const exchange = await deps.submitAndPoll(deps.identityTokenExchangePath(deps.routeCtx), deps.identityTokenExchangePollPath(deps.routeCtx), payload, pollOptions);
76
88
  return resolveTokenExchangeResult(exchange, normalizedScopes, tokenCacheKey, deps.setTokenCache);
77
89
  }
90
+ function joinRuntimeUrl(baseUrl, path) {
91
+ return `${String(baseUrl || '').replace(/\/+$/, '')}/${String(path || '').replace(/^\/+/, '')}`;
92
+ }
93
+ function normalizeResolvedSmartTokenEndpoint(value) {
94
+ const normalized = String(value || '').trim();
95
+ if (!normalized)
96
+ return undefined;
97
+ let endpoint;
98
+ try {
99
+ endpoint = new URL(normalized);
100
+ }
101
+ catch {
102
+ throw new Error('Resolved SMART token endpoint must be an absolute HTTP(S) URL.');
103
+ }
104
+ if (!['http:', 'https:'].includes(endpoint.protocol)) {
105
+ throw new Error('Resolved SMART token endpoint must use HTTP(S).');
106
+ }
107
+ if (!endpoint.pathname.endsWith('/identity/openid/smart/token')) {
108
+ throw new Error('Resolved SMART token endpoint must target /identity/openid/smart/token.');
109
+ }
110
+ return endpoint.toString();
111
+ }
112
+ function smartTokenPollEndpointFromTokenEndpoint(tokenEndpoint) {
113
+ const endpoint = new URL(tokenEndpoint);
114
+ endpoint.pathname = endpoint.pathname.replace(/\/identity\/openid\/smart\/token$/, '/identity/openid/smart/_batch-response');
115
+ return endpoint.toString();
116
+ }
78
117
  async function resolveClientAssertion(input) {
79
118
  const explicit = String(input.clientAssertion || '').trim();
80
119
  if (explicit)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-sdk-node-ts",
3
- "version": "2.3.4",
3
+ "version": "2.3.6",
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.",
@@ -36,8 +36,8 @@
36
36
  "test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
37
37
  },
38
38
  "dependencies": {
39
- "gdc-common-utils-ts": "^2.3.2",
40
- "gdc-sdk-core-ts": "~2.3.2"
39
+ "gdc-common-utils-ts": "^2.3.8",
40
+ "gdc-sdk-core-ts": "~2.3.5"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^20.14.10",