gdc-sdk-node-ts
v2.6.2
Published
Next-generation Node runtime package for the GDC SDK family
Readme
gdc-sdk-node-ts
See ARCHITECTURE.md and CONTRIBUTING.md before adding node runtime facades, execution adapters, or orchestration tests.
Short rule:
101tests must read like executable tutorialsgdc-common-utils-tsowns the canonical step-by-step editors/readers, shared fixtures, and reusable payload examplesgdc-sdk-node-tsstarts after that shared authoring step and atProfileRuntime -> loadProfile(...) -> workspace/session -> actor facadein node runtime tests
Node runtime package for consuming the shared GDC SDK contracts against real gateway backends.
Use this package when your backend needs to:
- call GW APIs
- submit/poll async operations
- orchestrate onboarding, consent, communication, and search flows
- consume the shared relationship invitation/acceptance contracts from
gdc-sdk-core-ts
This package is for runtime execution. It is not the place where the canonical business contract is defined.
Important test-harness boundary:
gdc-sdk-node-tsis not the product BFF- the live E2E suite simulates a controlled
virtual APIwith a BFF-like role only to validate GW CORE lifecycles end to end - the current live suites run with the future
user job managerqueue disabled, so every high-level call goes directly through that controlledvirtual API - app-side job queues, offline retry, local vault/read models, and the future user job manager are separate follow-up concerns
Important live-run rule:
- the canonical live E2E result must come from the user's real terminal/TTY
- do not assume an AI agent sandbox has equivalent localhost, Docker, DNS, or GCP connectivity
- if sandboxed runs disagree with the user's terminal, trust the user's terminal for live GW validation
Required live validation order:
- local process E2E from real TTY
- local Docker image/container E2E
- staging E2E
- production image/deploy only after staging is green
Architectural rule:
- shared contracts and actor boundaries come from
gdc-sdk-core-ts - this package executes those flows against GW
- this package should not widen an actor facade just because the runtime client happens to expose the underlying method
Start Here
If you are integrating this package for the first time, open these in order:
- gdc-sdk-core-ts/docs/101-SDK_PACKAGE_BOUNDARIES.md
Why
core,node, andfrontare separate packages, what belongs in each one, and why actor-scoped facades must stay aligned across runtimes. - docs/101-SDK_END_TO_END.md Ordered onboarding guide with end-to-end journeys, copy/paste snippets, and the recommended reading path for new backend integrators.
- docs/101-PROFESSIONAL-CONSENT-SMART.md Canonical professional DID, consent, VP and SMART flow without literal sections or caller-built audience URLs.
- docs/101-AUTHORIZED_SUBJECT_DIRECTORY.md Signed OpenID account discovery of already-authorized subjects without treating the account token as VP, SMART or wallet proof.
- docs/101-SDK_INTEGRATION.md
Real backend setup plus the public runtime entrypoints:
HostOnboardingSdk,OrganizationControllerSdk,IndividualControllerSdk,ProfessionalSdk, route-context usage, and the canonicalProfileRuntime -> loadProfile(...) -> workspace/session -> actor facade -> submit/pollshape. - tests/101-live-full-cycle-bff-runtime.e2e.test.mjs Canonical live backend/BFF walkthrough on a fresh local GW lifecycle: host/tenant activation, employee provisioning, individual bootstrap, consent grant, professional SMART token, clinical read, and final cleanup.
- docs/101-LIVE_GW_LOCAL.md Exact TTY/local/Docker commands for running the SDK against a real local GW CORE, including tenant bootstrap and employee-seat setup.
- docs/101-DISCOVERY.md Node/BFF dataspace discovery, hosting-operator resolution, provider resolution, and the correct integration boundary for fallback and cache.
- gdc-sdk-core-ts/docs/101-SDK_FLOWS.md Actor split and business-flow map across organization, individual, permissions, invitation, import, and SMART flows.
- gwtemplate-node-ts/docs/PORTAL_API_TO_GW_CORE.md
Canonical portal/BFF functional map over GW CORE, including the domain
split between
employees,related persons,members, andconsents. - gdc-common-utils-ts/src/examples/ Shared payload values used by the docs and tests.
- gdc-common-utils-ts/docs/101-LIFECYCLE.md
Canonical
enable/disable/deletesemantics and copy/paste placeholders. - tests/101-backend-profile-runtime.test.mjs Technical runtime slice for profile/device/session orchestration internals. Read this after the public actor SDK guides, not before them.
- tests/101-individual-controller-backend-runtime.test.mjs Technical wrapper slice around the generic profile runtime. This is not the main onboarding path for new integrators.
- docs/V2_INDIVIDUAL_REGISTRATION_RECONCILIATION.md Historical reconciliation note for the current CORE registration baseline.
- docs/NEXT_STEPS.md Follow-up scope after GW CORE live validation, including the future user job manager boundary.
If you need the shortest path:
- main onboarding guide: docs/101-SDK_END_TO_END.md
- wallet
context, stableruntimeIdand KMS-encrypted seed custody: docs/101-WALLET_CONTEXT_AND_KEY_CUSTODY.md - first public actor surfaces:
HostOnboardingSdk,OrganizationControllerSdk,IndividualControllerSdk,ProfessionalSdk - GW CORE app identity:
appIdmandatory,appVersionoptional with defaultv1.0 - backend technical identity:
initializeCommunicationIdentity(...)for the technical channel/runtime identity, not the legal organization id - runtime client:
NodeHttpClient - step-by-step runtime usage: docs/101-SDK_INTEGRATION.md
- dataspace discovery and fallback/cache boundary: docs/101-DISCOVERY.md
- strict local-first release order, zero-skip live evidence and the
from/iss/kid/SMARTsubplus native-FHIR boundary: docs/101-LIVE_GW_LOCAL.md
Current live teaching target:
- the main executable tutorial for integrators is now: tests/101-live-full-cycle-bff-runtime.e2e.test.mjs
- the standalone actor-profile suites still exist only as focused technical slices:
- the larger runtime suite remains the regression-oriented environment proof: tests/live-gw-node-runtime.e2e.test.mjs
Executable Usage Examples
Open these tests when you want to see exact method calls and exact inputs:
- tests/host-onboarding.test.mjs Organization activation and order confirmation.
- tests/individual-start.test.mjs Individual organization start flow.
- tests/individual-onboarding.test.mjs Individual order/offer confirmation flow.
- tests/device-activation.test.mjs Employee activation code and activation request flows.
- tests/resource-operations.test.mjs Related person upsert, communication ingestion, search, and access grants.
- tests/smart-token.test.mjs SMART token request flow.
- tests/live-gw-node-runtime.e2e.test.mjs End-to-end runtime wiring against a real GW environment.
- tests/101-live-full-cycle-bff-runtime.e2e.test.mjs
Single live BFF-oriented
101that chains tenant, professional, individual, consent, SMART, read, and cleanup in one executable conversation. - tests/live-profile-runtime-individual.e2e.test.mjs Standalone actor-profile E2E for the individual controller on an already operational tenant, including scenario-owned cleanup.
- tests/101-dataspace-resolver.test.mjs
Minimal
HttpDataspaceResolver101 with one host and one published provider. - tests/101-default-first-dataspace-discovery.test.mjs
Minimal
default-firstdiscovery with one host and one publishedIndexProvider.
Live GW CORE Flow
Use tests/101-live-full-cycle-bff-runtime.e2e.test.mjs
as the canonical live 101 for backend/BFF integrators.
Use tests/live-gw-node-runtime.e2e.test.mjs as the broader runtime-regression suite.
Before running that suite, read:
Execution requirement:
- run the live suite from a real user terminal/TTY
- if an AI agent is assisting, it should prefer a long-lived TTY process and avoid treating sandbox-local connectivity failures as product failures
Teaching rule:
- defaults come from
gdc-common-utils-ts/examples - override with env vars only when your tenant, bearer, or route is different
- local GW default is
http://127.0.0.1:3000 - Docker-exposed GW can be overridden with
BASE_URL=http://127.0.0.1:8000 LIVE_GW_E2E_EXECUTION_MODE=directis the current and only supported mode for live validation; queued app-side job management is a later phase
Current live 101 flow covered by the test suite:
- activate one hosted tenant / legal organization
- provision one professional employee through the organization controller
- load the individual-controller profile and bootstrap one hosted individual
- confirm the returned order and verify the invoice bundle projection
- ingest one IPS/clinical
Communicationwhose attached payload is the canonical documentBundlewithCompositionfirst entry - grant professional consent for one patient-summary section
- load the professional profile and request one SMART token
- read the allowed IPS bundle as the professional actor
- clean up consent, individual, employee, tenant, and host state
Run the main live 101:
npm run test:e2e:live-full-cycleWhat is still not fully covered as one single root lifecycle:
- initial organization license listing
- extra-seat activation after the portal-side fictitious payment confirmation
- relisting licenses after seat activation
- one employee bundle with employee
Aand employeeB - selective disable/purge validation across both employees
- consent escalation from partial IPS access to broader IPS access
- final cleanup of consent, individual, remaining employees, and tenant
Current invoice/readback behavior:
- both host and individual
Order/_batch-responseflows now return the flat compatibility claims and an embedded invoiceBundle - the invoice bundle contains one FHIR
Invoice, one PDFDocumentReference, and one structured JSON/XMLDocumentReference - live suites can read that bundle back through the same high-level response body that the virtual API exposes to the simulated front
Current runtime boundary:
OrganizationControllerSdk.confirmOrganizationLicenseOrder(...)now uses the public hostOrder/_batchroute used by GW CORE for portal-managed post-payment seat activation- that route is commercial routing only:
issremains the exact controller DID registered by tenant DCR,audremains the tenant id, and GW resolves its JWS/JWE key identifiers from the tenant rather than the host - applications use the high-level SDK method and configured transport profile;
they do not populate
meta.jws, move public keys, or construct DIDComm by hand - the long root lifecycle is still not fully closed because the suite does not
yet orchestrate the whole
license list -> pay -> confirm -> relist -> two employees -> selective purge -> cleanupdialogue as one single test
The exact pending release-readiness checklist lives in:
Optional live lifecycle extension:
- set
RUN_LIVE_GW_E2E_INDIVIDUAL_LIFECYCLE=1to extend the same suite withdisableIndividual(...)+purgeIndividual(...)against the realgwtemplate-node-tsruntime contract - this extra block is intentionally separate from the default happy path because it changes lifecycle state and should only run when that tenant/test subject is disposable
Shared example source of truth:
- tenant/route/controller/professional defaults: gdc-common-utils-ts/src/examples/shared.ts
- live employee defaults: gdc-common-utils-ts/src/examples/organization-controller.ts
- live consent defaults: gdc-common-utils-ts/src/examples/individual-controller.ts
The two medication defaults used by the live test are intentionally reusable:
Ibuprofen 400 mgParacetamol 600 mg- both every
8hours - both
PRN/dosage-asneeded = true - note text keeps the
4hour gap in English
Run the full live runtime baseline:
npm run test:e2e:live-gwSelect one live transport profile from the same Node entrypoint:
npm run test:e2e:live-gw:didcomm-plain
npm run test:e2e:live-gw:legacy-fhir
npm run test:e2e:live-gw:allProfile note:
didcomm-plainis the explicit demo-only live profilelegacy-fhirexercises rawapplication/fhir+jsonasync batch submission fororg.hl7.fhir.*allruns every implemented profile from the same suite file- each
NodeHttpClientselects one profile at construction; every facade operation and poll uses it and cannot override or downgrade it
Run the IPS ingestion/search branch as well:
RUN_LIVE_GW_E2E_IPS_INGESTION=1 \
npm run test:e2e:live-gwImplementation note:
- the beginner search story stays on FHIR parameters such as
Composition.section gdc-sdk-node-tssubmits the search request through the runtime facade- GW CORE resolves it internally from indexed subject sections and returns the consolidated IPS bundle document
Common overrides:
BASE_URL=http://127.0.0.1:3000 \
AUTH_BEARER=... \
TENANT_ID=VATES-B00112233 \
TENANT_ROUTE_ID=acme-live \
JURISDICTION=ES \
SECTOR=health-care \
SUBJECT_DID=did:web:api.acme.org:individual:123 \
RUN_LIVE_GW_E2E_IPS_INGESTION=1 \
LIVE_GW_NODE_E2E_DEBUG=1 \
npm run test:e2e:live-gwDocker-exposed GW example:
BASE_URL=http://127.0.0.1:8000 \
RUN_LIVE_GW_E2E_IPS_INGESTION=1 \
npm run test:e2e:live-gwDocumentation consistency rule for this repo family:
- scripts, README examples, Swagger examples, and internal tests must reuse the same example data and flow order
- if a new request/response example is added, add it first to
gdc-common-utils-ts/examplesand consume it from there instead of re-hardcoding values locally
Dataspace Discovery Quick Map
Use the Node discovery layer when your backend or BFF needs to:
- start from preloaded hosting-operator semantics
- fetch the canonical host-scoped
/<hosting-operator-network-context>/.well-known/dspace-versionentrypoint - derive the participant-scoped
/dsp/catalog/dcat.jsonartifact - return normalized provider/operator matches to portal or app backends
Primary references:
- docs/101-DISCOVERY.md
- tests/101-default-first-dataspace-discovery.test.mjs
- tests/101-dataspace-resolver.test.mjs
- tests/dataspace-resolver-advanced.test.mjs
- tests/dataspace-resolver.test.mjs
Architecture note:
- the reusable discovery resolver logic lives in
gdc-sdk-core-ts gdc-sdk-node-tsre-exports it and supplies the Node runtime surface
Copy/paste starting point:
import { createDefaultFirstDataspaceDiscovery } from 'gdc-sdk-node-ts';
import { DataspaceSectors } from 'gdc-common-utils-ts';
import { HostNetworkTypes } from 'gdc-common-utils-ts/constants/network';
const discovery = createDefaultFirstDataspaceDiscovery({
version: 'v1',
networkType: HostNetworkTypes.Test,
defaults,
});
const providers = await discovery.getIndexProviders({
sector: DataspaceSectors.AnimalCare,
jurisdiction: 'ES',
});Actor Split And Runtime Scope
This package must be understandable from the same actor split used by the shared contracts:
- organization controller
- organization employee / professional member
- individual controller
- individual member / self
- related person
- professional with consented access
The Node runtime layer is where those shared flows are executed against GW.
That includes organization onboarding, employee creation, individual bootstrap,
permission grants, RelatedPerson upserts, SMART token requests, and clinical
data ingestion/search.
Flow Families
- organization activation and order/offer confirmation
- employee creation and employee activation
- individual organization start and order confirmation
- related person upsert
- professional access grant
- invitation / OTP / relationship PIN runtime wiring
- permission-request
Communication - composed professional request submission and subject decision correlation
- communication ingestion and search
- SMART token retrieval
ProfessionalSdk.requestProfessionalAccess(...) is the bootstrap operation
for the inverse flow: it persists a subject-scoped permission-request
Communication using the configured HTTP bearer and transport profile, without
requiring SMART. The subject later answers through
respondToProfessionalAccessRequest(...); that facade uses the normal Consent
grant/deny operation and retains the original Communication identifier/thread.
listProfessionalAccessRequests(...) provides the subject/requester inbox view,
and GatewayActiveConsentProvider supplies evaluateRequestedAccess(...) from
the GW Consent source of truth rather than a parallel application table.
Main Flows
1. Controller invites a related person or professional
Typical backend sequence:
- build shared invitation payload with
gdc-sdk-core-ts - send it through the node runtime client or your backend adapter
- persist or return the invitation state to portal/app
What matters here:
- this package executes the runtime call
gdc-sdk-core-tsdefines the payload shape- callers should not hardcode route families in app code
2. Invitee accepts the relationship
Typical backend sequence:
- start OTP challenge
- confirm OTP
- set relationship PIN if required
- activate the relationship channel
Shared contract builders come from gdc-sdk-core-ts; this package is where a
Node backend wires them to real runtime operations.
3. Consent-aware communication and search
Use this package when your backend needs to:
- ingest
Communication - search clinical bundles
- request SMART tokens
- grant access
- create or update
RelatedPerson
What This Package Owns
- Node runtime client
- submit/poll orchestration
- actor-scoped node sessions
- backend-facing orchestration helpers
What This Package Does Not Own
- the canonical invitation/OTP/PIN contract
- application-specific reminder runtime semantics
- frontend session UX
Those belong to:
gdc-sdk-core-tsfor shared contracts- runtime extensions for product-specific behavior
gdc-sdk-front-tsfor frontend-facing consumption
Minimal Examples
Use shared invitation contract from Node
import {
createRelationshipChannelInvitationInput,
RelationshipAccessActorKinds,
RelationshipEnrollmentChannels,
type RelationshipChannelInvitationInput,
} from 'gdc-sdk-core-ts';
import {
buildIndividualDidWeb,
HealthcareActorRoles,
HealthcareConsentPurposes,
} from 'gdc-common-utils-ts';
const tenantId = 'acme-id';
const jurisdiction = 'ES';
const sector = 'health-care';
const providerOrganizationDid = subjectProfile.organizationDid;
const subjectLocalId = subjectProfile.subjectId;
const subjectId = buildIndividualDidWeb({
organizationDidWeb: providerOrganizationDid,
subjectId: subjectLocalId,
});
const professionalEmail = invitedProfessional.email;
const invitationInput: RelationshipChannelInvitationInput = {
tenantId,
jurisdiction,
sector,
subjectId,
subjectKind: 'person',
actorKind: RelationshipAccessActorKinds.Professional,
actorIdentifier: professionalEmail,
actorRole: HealthcareActorRoles.Physician,
deliveryChannel: RelationshipEnrollmentChannels.Email,
deliveryTarget: professionalEmail,
purpose: HealthcareConsentPurposes.Treatment,
relationshipLabel: 'primary-physician',
phonePinOptional: false,
};
const invitation = createRelationshipChannelInvitationInput(invitationInput);The backend should obtain those variables from:
- tenant route selection
- target subject identifier
- invited actor identity
- selected enrollment channel
- intended purpose/relationship label
Request SMART token and search bundle
import { NodeHttpClient } from 'gdc-sdk-node-ts';
import {
EXAMPLE_LATEST_IPS_SEARCH_INPUT,
} from 'gdc-common-utils-ts/examples/individual-controller';
import { HealthcareBasicSections } from 'gdc-common-utils-ts/constants/healthcare';
import { buildSmartCompositionReadScope } from 'gdc-common-utils-ts/utils/smart-scope';
const client = new NodeHttpClient({ baseUrl: process.env.BASE_URL! });
const subjectDid = EXAMPLE_LATEST_IPS_SEARCH_INPUT.subject;
const token = await client.requestSmartToken({
ctx,
actorDid: 'did:web:doctor.example.org:employee:001',
subjectDid,
scopes: [
buildSmartCompositionReadScope({
subjectDid,
sections: HealthcareBasicSections.PatientSummaryDocument.claim,
}),
],
idToken: '...',
});
const result = await client.searchClinicalBundle(ctx, {
subject: subjectDid,
});Teaching rule:
- start with the composition read scope when the actor only needs subject-scoped read access
- add
SmartGatewayScopesFhirR4.ConsentCrudsonly if the backend also needs consent management operations
Shared Contract Sources
Reusable payload examples:
- gdc-common-utils-ts/src/examples/organization-controller.ts
- gdc-common-utils-ts/src/examples/individual-controller.ts
- gdc-common-utils-ts/src/examples/professional.ts
- gdc-common-utils-ts/src/examples/shared.ts
- gdc-common-utils-ts/src/examples/lifecycle.ts
- gdc-common-utils-ts/src/examples/api-flow-examples.ts
Local terminology route for Next.js
LocalTerminologyBffService keeps complete JSON catalogs in the application
BFF and returns only matching options:
const terminology = new LocalTerminologyBffService(catalogs);
export async function GET(request: Request) {
const url = new URL(request.url);
return Response.json(terminology.search({
text: url.searchParams.get('text') || '',
language: url.searchParams.get('language') || 'en',
jurisdiction: url.searchParams.get('jurisdiction') || undefined,
systems: url.searchParams.getAll('system'),
limit: 20,
}));
}The application validates which systems are allowed for the specific coded form field. This MVP service performs no external terminology request.
API Index
Full Public Surface
This package exports the full gdc-sdk-core-ts surface plus the Node runtime
modules below.
src/runtime-contracts.ts- types/constants:
LegacyNodeSourcePackage,NodeRuntimeMode,NodeInteropMode,TenantContext,NodeOperatorContext,NodeFetchLike,NodeRuntimeConfig,NodePackageStatus,GDC_SDK_NODE_STATUS
- types/constants:
src/identity-bootstrap.ts- function:
initializeCommunicationIdentity(...)
- function:
src/async-polling.ts- types:
AcceptedPollResponse - function:
pollUntilCompleteWithMethod(...)
- types:
src/poll-options.ts- re-export:
resolvePollOptionsFromSeconds(...)
- re-export:
src/host-onboarding.ts- types:
HostRouteContext,LegalOrganizationOrderInput - function:
confirmLegalOrganizationOrderWithDeps(...)
- types:
src/individual-start.ts- types:
IndividualOrganizationBootstrapInput,OfferPreview,IndividualOrganizationStartResult - function:
startIndividualOrganizationWithDeps(...)
- types:
src/individual-onboarding.ts- types:
RouteContext,IndividualOrganizationConfirmOrderInput - function:
confirmIndividualOrganizationOrderWithDeps(...)
- types:
src/device-activation.ts- types:
EmployeeDeviceActivationInput,EmployeeDeviceActivationRequestInput,EmployeeDeviceActivationResult - functions:
activateEmployeeDeviceWithActivationCodeWithDeps(...),activateEmployeeDeviceWithActivationRequestWithDeps(...)
- types:
src/smart-token.ts- types:
SmartTokenRequestInput,SmartTokenExchangeResult - function:
requestSmartTokenWithDeps(...)
- types:
src/resource-operations.ts- types:
OrganizationEmployeeCreationInput,IpsOrFhirImportInput,RelatedPersonUpsertInput,CommunicationIngestionInput,ClinicalDateRange,ClinicalBundleSearchInput,ConsentActorTargetInput,GrantProfessionalAccessInput,GrantProfessionalAccessResult,DigitalTwinSecondaryUseConsentInput,DigitalTwinSubjectLinkPurgeInput,SubjectConsentSearchInput - functions:
createOrganizationEmployeeWithDeps(...),importIpsOrFhirAndUpdateIndexWithDeps(...),upsertRelatedPersonAndPollWithDeps(...),ingestCommunicationAndUpdateIndexWithDeps(...),searchClinicalBundleWithDeps(...),searchSubjectConsentsWithDeps(...),searchLatestIpsWithDeps(...),grantProfessionalAccessWithDeps(...),setDigitalTwinSecondaryUseConsentWithDeps(...),purgeDigitalTwinSubjectLinkWithDeps(...)
- types:
src/digital-twin.ts- types:
DigitalTwinSearchInput,DigitalTwinSelectionInput,DigitalTwinResearchTag,DigitalTwinMaterializationInput - functions:
searchDigitalTwinsWithDeps(...),saveDigitalTwinSelectionWithDeps(...),materializeDigitalTwinWithDeps(...)
- types:
src/orchestration/digital-twin-sdk.ts- class:
DigitalTwinSdk(requestSmartToken,search,saveSelection,searchSelections,materialize); both searches exposeResearchSubjectthrough FHIR Parameters, with its canonical internal Composition available ascomposition
- class:
src/session.ts- types:
NodeCapability,NodeActorSessionContext,ActorSessionContext - classes:
ActorSession,NodeActorSession
- types:
src/node-runtime-client.ts- types:
HttpRuntimeClientOptions,NodeHttpClientOptions - classes:
HttpRuntimeClient,NodeHttpClient
- types:
src/gdc-session-bridge.ts- functions:
createNodeActorSessionsFromFacades(...),createNodeActorSessionFromFacade(...),createNodeActorSessionsFromDescriptor(...),createNodeActorSessionFromDescriptor(...),createActorSessionsFromFacades(...),createActorSessionFromFacade(...),createActorSessionsFromDescriptor(...),createActorSessionFromDescriptor(...)
- functions:
src/orchestration/client-port.ts- types:
RuntimeClient,NodeRuntimeClient - functions:
requireClientMethod(...),submitAndPollWithMethods(...),canClientSubmitAndPoll(...),submitAndPollWithClient(...)
- types:
src/orchestration/host-onboarding-sdk.ts- class:
HostOnboardingSdk
- class:
src/orchestration/organization-controller-sdk.ts- class:
OrganizationControllerSdk
- class:
src/orchestration/organization-employee-sdk.ts- class:
OrganizationEmployeeSdk
- class:
src/orchestration/individual-controller-sdk.ts- class:
IndividualControllerSdk
- class:
src/orchestration/individual-member-sdk.ts- class:
IndividualMemberSdk
- class:
src/orchestration/personal-sdk.ts- class:
PersonalSdk
- class:
src/orchestration/professional-sdk.ts- class:
ProfessionalSdk
- class:
src/legacy-compat.ts- compatibility aliases for simplified helpers, runtime classes, and legacy names such as
GdcNodeActorSessionandGdcNodeHttpClient
- compatibility aliases for simplified helpers, runtime classes, and legacy names such as
Re-exported shared helpers from gdc-sdk-core-ts
- consent access helpers
- relationship invitation/acceptance builders
- communication/document builders
- draft/outbox helpers
- document facade helpers
- vital-sign helpers
Node runtime client
NodeHttpClientNodeHttpClient.submitLegalOrganizationVerificationTransaction(...)NodeHttpClient.ingestCommunicationAndUpdateIndex(...)NodeHttpClient.submitCommunicationAndPoll(...)NodeHttpClient.searchClinicalBundle(...)NodeHttpClient.updateClinicalSection(...)for one explicit section carried by a batch Communication; its typed entries may mix.create(),.update()and exact authored.delete()operationsNodeHttpClient.updateClinicalSummary(...)for a Composition-first multi-section documentNodeHttpClient.searchLatestIps(...)NodeHttpClient.grantProfessionalAccess(...)NodeHttpClient.requestSmartToken(...)
Runtime configuration
Low-level orchestration helpers
createOrganizationEmployeeWithDeps(...)importIpsOrFhirAndUpdateIndexWithDeps(...)upsertRelatedPersonAndPollWithDeps(...)ingestCommunicationAndUpdateIndexWithDeps(...)searchClinicalBundleWithDeps(...)searchLatestIpsWithDeps(...)grantProfessionalAccessWithDeps(...)
Documentation Rule
- README explains backend-facing flows first.
- Shared contract shapes must be documented in
gdc-sdk-core-ts, not duplicated here. - Route details and GW-specific behavior belong in runtime docs and JSDoc, not in app-facing examples.
Host Onboarding Runtime Flow
For legal-organization onboarding from a Node BFF/runtime, keep the host steps separate:
- new flow:
Organization/_transaction - legacy compatibility flow:
ICA _verify -> Organization/_activate - downstream business continuation:
Order/_batch
Use OrganizationControllerSdk.submitLegalOrganizationVerificationTransaction(...) or
NodeHttpClient.submitLegalOrganizationVerificationTransaction(...) for step 1.
Existing-tenant recovery/reverification:
- use
OrganizationControllerSdk.submitLegalOrganizationCredentialReissuance(...)orNodeHttpClient.submitLegalOrganizationCredentialReissuance(...)to refresh the ICA-backed verification for an already registered tenant without creating a new Offer - inside the terminal decoded GW Bundle, the canonical polled response keeps
all deduplicated ICA-issued credentials in
body.data[0].vc[]and the complete ICA payload inbody.data[0].resource.icaResponse; SDK callers receive that terminal HTTP payload asSubmitAndPollResult.poll.body - separately, GW returns the controller License activation code in
body.data[0].meta.claims['org.schema.IndividualProduct.serialNumber'] Organization/_issueis notLicense/_issue: the activation code is not a VC andLicense:Issuedis not the canonical response entry type for this route- then continue with the existing helper chain:
recoverOrganizationControllerWithCredentialReissuanceWithDeps(...)or directly_exchange -> _dcr submitLegalOrganizationIssue(...)remains only as a deprecated alias named after the underlyingOrganization/_issueroute- for a reproducible local/staging runtime check, use:
npm run test:e2e:live-gw:issue-recovery - for the deterministic controller-lifecycle contract that also proves post-registration seat preservation and final tenant teardown, use: docs/101-ORGANIZATION_CONTROLLER_LIFECYCLE.md
Rules:
_transactionand_activateare different flows- transport/runtime communication keys stay outside the business payload
- controller binding key stays in
body.data[].resource.controller.* - do not mix this path with
requestIcaEnrollmentor Fabric
Legacy compatibility coverage in the live suite:
- the canonical test is
LIVE professional lifecycle on GW - set
RUN_LIVE_GW_E2E_HOST_VERIFICATION_TRANSACTION=1to exercise:Organization/_transaction -> Order/_batch
- set
RUN_LIVE_GW_E2E_HOST_VERIFICATION_TRANSACTION=0to exercise the older:ICA _verify -> Organization/_activate -> Order/_batch
Dedicated legacy live command:
cd /Users/fernando/GITS/gdc-workspace/gdc-sdk-node-ts
RUN_LIVE_GW_E2E=1 \
RUN_LIVE_GW_E2E_ACTOR_CHAIN=1 \
RUN_LIVE_GW_E2E_HOST_VERIFICATION_TRANSACTION=0 \
LIVE_GW_E2E_SUITE=professional \
node --test tests/live-gw-node-runtime.e2e.test.mjsLive E2E legal PDF source:
- local file: set
LIVE_GW_HOST_VERIFICATION_PDF_PATH=/abs/path/file.pdf - public URL: set
LIVE_GW_HOST_VERIFICATION_PDF_URL=https://.../file.pdf - if both are present, the live suite prefers
LIVE_GW_HOST_VERIFICATION_PDF_URL - Dropbox-style links are normalized to
dl=1direct-download mode automatically
Recovery-specific live rule:
Organization/_issuecan succeed and still be followed by_exchangefailure if the controllerid_tokenis invalid, expired or does not prove the expected actor/contact- the current GW
_exchangepath expects a valid IdP token but takes tenant authority from the already validated request route - a custom
tenant_idclaim is optional; when present it must match the route and cannot select another tenant - a failed poll
OperationOutcomeis surfaced before the helper checks forinitial_access_token, preserving the real GW diagnostic - the bundled recovery runner generates a syntactically valid demo JWT if
CONTROLLER_ID_TOKENis not provided, but production/staging should use a real IdP-issued token
Minimal live recovery command:
PDF_PATH=/Users/fernando/GITS/gdc-workspace/examples/TEST-A4-Antifraud.pdf \
BASE_URL=http://127.0.0.1:3000 \
TENANT_ID=acme-id \
npm run test:e2e:live-gw:issue-recovery