gdc-sdk-node-ts 2.3.17 → 2.3.19

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
@@ -406,9 +406,20 @@ data ingestion/search.
406
406
  - professional access grant
407
407
  - invitation / OTP / relationship PIN runtime wiring
408
408
  - permission-request `Communication`
409
+ - composed professional request submission and subject decision correlation
409
410
  - communication ingestion and search
410
411
  - SMART token retrieval
411
412
 
413
+ `ProfessionalSdk.requestProfessionalAccess(...)` is the bootstrap operation
414
+ for the inverse flow: it persists a subject-scoped permission-request
415
+ `Communication` using the configured HTTP bearer and transport profile, without
416
+ requiring SMART. The subject later answers through
417
+ `respondToProfessionalAccessRequest(...)`; that facade uses the normal Consent
418
+ grant/deny operation and retains the original Communication identifier/thread.
419
+ `listProfessionalAccessRequests(...)` provides the subject/requester inbox view,
420
+ and `GatewayActiveConsentProvider` supplies `evaluateRequestedAccess(...)` from
421
+ the GW Consent source of truth rather than a parallel application table.
422
+
412
423
  ## Main Flows
413
424
 
414
425
  ### 1. Controller invites a related person or professional
@@ -0,0 +1,19 @@
1
+ import { type ConsentRule } from 'gdc-common-utils-ts/models/consent-rule';
2
+ import type { ActiveConsentProvider } from 'gdc-sdk-core-ts';
3
+ import type { RouteContext } from './individual-onboarding.js';
4
+ import { type NodeRuntimeClient } from './orchestration/client-port.js';
5
+ /**
6
+ * GW-backed implementation of the runtime-neutral ActiveConsentProvider.
7
+ *
8
+ * The configured client decides HTTP authentication and transport protection.
9
+ * This adapter does not introduce an application-owned Consent table.
10
+ */
11
+ export declare class GatewayActiveConsentProvider implements ActiveConsentProvider {
12
+ private readonly client;
13
+ private readonly routeContext;
14
+ constructor(client: NodeRuntimeClient, routeContext: RouteContext);
15
+ /** Loads and normalizes the active Consent rules owned by one subject. */
16
+ getActiveConsentsForSubject(subject: string): Promise<ConsentRule[]>;
17
+ }
18
+ /** Extracts canonical Consent claim maps from current GW Bundle wrappers. */
19
+ export declare function extractConsentRules(value: unknown): ConsentRule[];
@@ -0,0 +1,70 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ import { ResourceTypesFhirR4 } from 'gdc-common-utils-ts/constants/fhir-resource-types';
3
+ import { ClaimConsent } from 'gdc-common-utils-ts/models/consent-rule';
4
+ import { isConsentRuleActive } from 'gdc-common-utils-ts/utils/consent';
5
+ import { requireClientMethod } from './orchestration/client-port.js';
6
+ /**
7
+ * GW-backed implementation of the runtime-neutral ActiveConsentProvider.
8
+ *
9
+ * The configured client decides HTTP authentication and transport protection.
10
+ * This adapter does not introduce an application-owned Consent table.
11
+ */
12
+ export class GatewayActiveConsentProvider {
13
+ constructor(client, routeContext) {
14
+ this.client = client;
15
+ this.routeContext = routeContext;
16
+ }
17
+ /** Loads and normalizes the active Consent rules owned by one subject. */
18
+ async getActiveConsentsForSubject(subject) {
19
+ const normalizedSubject = String(subject || '').trim();
20
+ if (!normalizedSubject.startsWith('did:')) {
21
+ throw new Error('Active Consent lookup requires a subject DID.');
22
+ }
23
+ const result = await requireClientMethod(this.client, 'searchClinicalBundle')(this.routeContext, {
24
+ subject: normalizedSubject,
25
+ includedTypes: [ResourceTypesFhirR4.Consent],
26
+ });
27
+ return extractConsentRules(result.poll.body)
28
+ .filter((rule) => isConsentRuleActive(rule, { subject: normalizedSubject }));
29
+ }
30
+ }
31
+ /** Extracts canonical Consent claim maps from current GW Bundle wrappers. */
32
+ export function extractConsentRules(value) {
33
+ const candidates = [];
34
+ const seenObjects = new Set();
35
+ const seenRules = new Set();
36
+ function visit(node) {
37
+ if (!node || typeof node !== 'object')
38
+ return;
39
+ if (seenObjects.has(node))
40
+ return;
41
+ seenObjects.add(node);
42
+ if (Array.isArray(node)) {
43
+ node.forEach(visit);
44
+ return;
45
+ }
46
+ const record = node;
47
+ const claims = record.claims && typeof record.claims === 'object'
48
+ ? record.claims
49
+ : undefined;
50
+ for (const candidate of [record, claims]) {
51
+ if (!candidate || !looksLikeConsentRule(candidate))
52
+ continue;
53
+ const rule = candidate;
54
+ const key = String(rule[ClaimConsent.identifier] || JSON.stringify(rule));
55
+ if (!seenRules.has(key)) {
56
+ seenRules.add(key);
57
+ candidates.push(rule);
58
+ }
59
+ }
60
+ Object.values(record).forEach(visit);
61
+ }
62
+ visit(value);
63
+ return candidates;
64
+ }
65
+ function looksLikeConsentRule(value) {
66
+ return Boolean(String(value[ClaimConsent.subject] || '').trim()
67
+ && String(value[ClaimConsent.actorIdentifier] || '').trim()
68
+ && String(value[ClaimConsent.decision] || '').trim()
69
+ && String(value[ClaimConsent.action] || '').trim());
70
+ }
package/dist/index.d.ts CHANGED
@@ -29,6 +29,7 @@ export * from './node-managed-wallet.js';
29
29
  export * from './did-web-recipient.js';
30
30
  export * from './constants/lifecycle.js';
31
31
  export * from './consent-claim-helpers.js';
32
+ export * from './gateway-active-consent-provider.js';
32
33
  export * from './session.js';
33
34
  export * from './node-runtime-client.js';
34
35
  export * from './gdc-session-bridge.js';
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ export * from './node-managed-wallet.js';
30
30
  export * from './did-web-recipient.js';
31
31
  export * from './constants/lifecycle.js';
32
32
  export * from './consent-claim-helpers.js';
33
+ export * from './gateway-active-consent-provider.js';
33
34
  export * from './session.js';
34
35
  export * from './node-runtime-client.js';
35
36
  export * from './gdc-session-bridge.js';
@@ -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 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';
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 ProfessionalAccessRequestInput, type ProfessionalAccessRequestResult, 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';
@@ -409,6 +409,12 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
409
409
  * @param input Communication payload plus route/format options.
410
410
  */
411
411
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
412
+ /**
413
+ * Records a subject-scoped permission-request Communication before SMART
414
+ * authorization exists. The configured bearer authenticates HTTP and the
415
+ * configured secure transport adapter signs/encrypts DIDComm when enabled.
416
+ */
417
+ requestProfessionalAccess(ctx: RouteContext, input: ProfessionalAccessRequestInput): Promise<ProfessionalAccessRequestResult>;
412
418
  /**
413
419
  * Updates exactly one clinical section.
414
420
  *
@@ -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, 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';
15
+ import { createOrganizationEmployeeWithDeps, disableIndividualMemberWithDeps, disableIndividualOrganizationWithDeps, disableOrganizationEmployeeWithDeps, listIndividualLicenseOffersWithDeps, listIndividualLicenseOrdersWithDeps, listIndividualLicensesWithDeps, addFreeIndividualMemberLicensesWithDeps, issueIndividualMemberLicenseWithDeps, transitionIndividualMemberLicenseWithDeps, listOrganizationLicenseOffersWithDeps, listOrganizationLicenseOrdersWithDeps, listOrganizationLicensesWithDeps, grantProfessionalAccessWithDeps, buildClinicalSectionUpdateIngestion, buildClinicalSummaryUpdateIngestion, ingestCommunicationAndUpdateIndexWithDeps, requestProfessionalAccessWithDeps, buildVitalSignBatchCommunicationFromSearchResponse, registerBlockchainArtifactAndUpdateIndexWithDeps, requestClinicalSummaryWithDeps, revokeProfessionalAccessWithDeps, searchCommunicationParticipantsWithDeps, purgeIndividualMemberWithDeps, purgeIndividualOrganizationWithDeps, purgeOrganizationEmployeeWithDeps, prepareEmployeeLifecycleMessageForTransport, 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';
@@ -328,7 +328,7 @@ export class HttpRuntimeClient {
328
328
  return createOrganizationEmployeeWithDeps(ctx, input, pollOptions, {
329
329
  employeeBatchPath: this.paths.employeeBatchPath.bind(this.paths),
330
330
  employeePollPath: this.paths.employeePollPath.bind(this.paths),
331
- submitAndPoll: this.submitAndPoll.bind(this),
331
+ submitAndPoll: (submitPath, pollPath, payload, options) => this.submitClinicalMessageAndPoll(submitPath, pollPath, prepareEmployeeLifecycleMessageForTransport(payload, this.transportProfile), this.transportProfile, options),
332
332
  });
333
333
  }
334
334
  /**
@@ -749,6 +749,18 @@ export class HttpRuntimeClient {
749
749
  submitAndPoll: this.submitAndPoll.bind(this),
750
750
  });
751
751
  }
752
+ /**
753
+ * Records a subject-scoped permission-request Communication before SMART
754
+ * authorization exists. The configured bearer authenticates HTTP and the
755
+ * configured secure transport adapter signs/encrypts DIDComm when enabled.
756
+ */
757
+ async requestProfessionalAccess(ctx, input) {
758
+ return requestProfessionalAccessWithDeps(ctx, input, {
759
+ individualCommunicationBatchPath: this.paths.individualCommunicationBatchPath.bind(this.paths),
760
+ individualCommunicationPollPath: this.paths.individualCommunicationPollPath.bind(this.paths),
761
+ submitAndPoll: (submitPath, pollPath, payload, pollOptions) => this.submitClinicalMessageAndPoll(submitPath, pollPath, payload, input.transportProfile || this.transportProfile, pollOptions),
762
+ });
763
+ }
752
764
  /**
753
765
  * Updates exactly one clinical section.
754
766
  *
@@ -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, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, 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, ProfessionalAccessRequestInput, ProfessionalAccessRequestResult, RevokeProfessionalAccessInput, RevokeProfessionalAccessResult, RelatedPersonUpsertInput } from '../resource-operations.js';
17
17
  /**
18
18
  * Shared node-runtime activation input.
19
19
  *
@@ -89,6 +89,7 @@ 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
+ requestProfessionalAccess?: (ctx: RouteContext, input: ProfessionalAccessRequestInput) => Promise<ProfessionalAccessRequestResult>;
92
93
  updateClinicalSection?: (ctx: RouteContext, input: ClinicalSectionUpdateInput) => Promise<SubmitAndPollResult>;
93
94
  updateClinicalSummary?: (ctx: RouteContext, input: ClinicalSummaryUpdateInput) => Promise<SubmitAndPollResult>;
94
95
  requestClinicalSummary?: (ctx: RouteContext, input: ClinicalSummaryRequestInput) => Promise<ClinicalSummaryReadResult>;
@@ -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, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, 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, ProfessionalAccessRequestDecisionInput, ProfessionalAccessRequestSearchInput, 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`.
@@ -70,6 +70,10 @@ export declare class IndividualControllerSdk {
70
70
  * Grants access to a professional through a consent flow.
71
71
  */
72
72
  grantProfessionalAccess(ctx: RouteContext, input: GrantProfessionalAccessInput): Promise<GrantProfessionalAccessResult>;
73
+ /** Approves or denies a permission request while retaining its correlation. */
74
+ respondToProfessionalAccessRequest(ctx: RouteContext, input: ProfessionalAccessRequestDecisionInput): Promise<GrantProfessionalAccessResult>;
75
+ /** Lists canonical permission requests addressed to this subject. */
76
+ listProfessionalAccessRequests(ctx: RouteContext, input: ProfessionalAccessRequestSearchInput): Promise<SubmitAndPollResult>;
73
77
  /**
74
78
  * Closes an existing professional consent by setting its period end.
75
79
  */
@@ -3,6 +3,8 @@ import { ActorCapabilities, ActorKinds } from 'gdc-common-utils-ts/constants/act
3
3
  import { buildIndividualControllerIdentityVpPayload, buildUnsignedIndividualControllerIdentityVpJwt, getIndividualControllerIdentitySameAs, getIndividualControllerIdentityVC, getIndividualSubjectVC, } from 'gdc-common-utils-ts';
4
4
  import { requireClientMethod, submitAndPollWithClient, } from './client-port.js';
5
5
  import { assertFacadeCapability } from './capability-guard.js';
6
+ import { buildProfessionalAccessRequestDecisionGrant } from '../resource-operations.js';
7
+ import { buildProfessionalAccessRequestSearchInput } from '../resource-operations.js';
6
8
  /**
7
9
  * Individual-controller oriented facade over a `NodeRuntimeClient`.
8
10
  *
@@ -96,6 +98,15 @@ export class IndividualControllerSdk {
96
98
  assertFacadeCapability(this.capabilities, ActorCapabilities.ConsentGrantProfessionalAccess, ActorKinds.IndividualController, 'grantProfessionalAccess');
97
99
  return requireClientMethod(this.client, 'grantProfessionalAccess')(ctx, input);
98
100
  }
101
+ /** Approves or denies a permission request while retaining its correlation. */
102
+ respondToProfessionalAccessRequest(ctx, input) {
103
+ assertFacadeCapability(this.capabilities, ActorCapabilities.ConsentGrantProfessionalAccess, ActorKinds.IndividualController, 'respondToProfessionalAccessRequest');
104
+ return requireClientMethod(this.client, 'grantProfessionalAccess')(ctx, buildProfessionalAccessRequestDecisionGrant(input));
105
+ }
106
+ /** Lists canonical permission requests addressed to this subject. */
107
+ listProfessionalAccessRequests(ctx, input) {
108
+ return requireClientMethod(this.client, 'searchCommunicationParticipants')(ctx, buildProfessionalAccessRequestSearchInput(input));
109
+ }
99
110
  /**
100
111
  * Closes an existing professional consent by setting its period end.
101
112
  */
@@ -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, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, 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, ProfessionalAccessRequestDecisionInput, ProfessionalAccessRequestSearchInput, 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;
@@ -10,6 +10,10 @@ export declare class PersonalSdk {
10
10
  startIndividualOrganization(input: IndividualOrganizationBootstrapInput): Promise<IndividualOrganizationStartResult>;
11
11
  /** Grants professional access via Consent for a subject. */
12
12
  grantProfessionalAccess(ctx: RouteContext, input: GrantProfessionalAccessInput): Promise<GrantProfessionalAccessResult>;
13
+ /** Approves or denies a permission request while retaining its correlation. */
14
+ respondToProfessionalAccessRequest(ctx: RouteContext, input: ProfessionalAccessRequestDecisionInput): Promise<GrantProfessionalAccessResult>;
15
+ /** Lists canonical permission requests addressed to this subject. */
16
+ listProfessionalAccessRequests(ctx: RouteContext, input: ProfessionalAccessRequestSearchInput): Promise<SubmitAndPollResult>;
13
17
  /** Imports IPS/FHIR payload and updates document index projections. */
14
18
  importIpsOrFhirAndUpdateIndex(ctx: RouteContext, input: IpsOrFhirImportInput): Promise<SubmitAndPollResult>;
15
19
  /** Ingests canonical Communication and waits for projection completion. */
@@ -1,5 +1,7 @@
1
1
  // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
2
  import { requireClientMethod, submitAndPollWithClient, } from './client-port.js';
3
+ import { buildProfessionalAccessRequestDecisionGrant } from '../resource-operations.js';
4
+ import { buildProfessionalAccessRequestSearchInput } from '../resource-operations.js';
3
5
  export class PersonalSdk {
4
6
  constructor(client) {
5
7
  this.client = client;
@@ -12,6 +14,14 @@ export class PersonalSdk {
12
14
  grantProfessionalAccess(ctx, input) {
13
15
  return requireClientMethod(this.client, 'grantProfessionalAccess')(ctx, input);
14
16
  }
17
+ /** Approves or denies a permission request while retaining its correlation. */
18
+ respondToProfessionalAccessRequest(ctx, input) {
19
+ return requireClientMethod(this.client, 'grantProfessionalAccess')(ctx, buildProfessionalAccessRequestDecisionGrant(input));
20
+ }
21
+ /** Lists canonical permission requests addressed to this subject. */
22
+ listProfessionalAccessRequests(ctx, input) {
23
+ return requireClientMethod(this.client, 'searchCommunicationParticipants')(ctx, buildProfessionalAccessRequestSearchInput(input));
24
+ }
15
25
  /** Imports IPS/FHIR payload and updates document index projections. */
16
26
  importIpsOrFhirAndUpdateIndex(ctx, input) {
17
27
  return requireClientMethod(this.client, 'importIpsOrFhirAndUpdateIndex')(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, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, VitalSignBatchCommunicationFromSearchResponseInput } from '../resource-operations.js';
5
+ import type { BlockchainArtifactRegistrationInput, CommunicationIngestionInput, CommunicationParticipantRuntimeSearchInput, ClinicalBundleSearchInput, ClinicalSectionUpdateInput, ClinicalSummaryReadResult, ClinicalSummaryRequestInput, ClinicalSummaryUpdateInput, GrantProfessionalAccessInput, GrantProfessionalAccessResult, ProfessionalAccessRequestInput, ProfessionalAccessRequestResult, ProfessionalAccessRequestSearchInput, 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
@@ -75,6 +75,13 @@ export declare class ProfessionalSdk {
75
75
  * Ingests a FHIR `Communication` and waits for indexing.
76
76
  */
77
77
  ingestCommunicationAndUpdateIndex(ctx: RouteContext, input: CommunicationIngestionInput): Promise<SubmitAndPollResult>;
78
+ /**
79
+ * Requests subject-controlled access without requiring a SMART token. The
80
+ * runtime persists one canonical permission-request Communication.
81
+ */
82
+ requestProfessionalAccess(ctx: RouteContext, input: ProfessionalAccessRequestInput): Promise<ProfessionalAccessRequestResult>;
83
+ /** Lists permission requests sent by or involving this professional. */
84
+ listProfessionalAccessRequests(ctx: RouteContext, input: ProfessionalAccessRequestSearchInput): Promise<SubmitAndPollResult>;
78
85
  /** Updates one consent-authorized clinical section through a scoped batch/collection. */
79
86
  updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<SubmitAndPollResult>;
80
87
  /** Updates a consent-authorized multi-section summary document. */
@@ -2,6 +2,7 @@
2
2
  // Always create JSDoc, do not use strings inline in keys nor values, use types instead, and reuse the data test examples.
3
3
  import { buildProfessionalIdentityVpPayload, buildUnsignedProfessionalIdentityVpJwt, getProfessionalIdentitySameAs, getProfessionalIdentityVC, } from 'gdc-common-utils-ts';
4
4
  import { requireClientMethod, submitAndPollWithClient, } from './client-port.js';
5
+ import { buildProfessionalAccessRequestSearchInput } from '../resource-operations.js';
5
6
  /**
6
7
  * Professional-oriented facade for runtime actions that belong to the
7
8
  * professional actor itself after tenant and employee provisioning have already
@@ -89,6 +90,17 @@ export class ProfessionalSdk {
89
90
  ingestCommunicationAndUpdateIndex(ctx, input) {
90
91
  return requireClientMethod(this.client, 'ingestCommunicationAndUpdateIndex')(ctx, input);
91
92
  }
93
+ /**
94
+ * Requests subject-controlled access without requiring a SMART token. The
95
+ * runtime persists one canonical permission-request Communication.
96
+ */
97
+ requestProfessionalAccess(ctx, input) {
98
+ return requireClientMethod(this.client, 'requestProfessionalAccess')(ctx, input);
99
+ }
100
+ /** Lists permission requests sent by or involving this professional. */
101
+ listProfessionalAccessRequests(ctx, input) {
102
+ return requireClientMethod(this.client, 'searchCommunicationParticipants')(ctx, buildProfessionalAccessRequestSearchInput(input));
103
+ }
92
104
  /** Updates one consent-authorized clinical section through a scoped batch/collection. */
93
105
  updateClinicalSection(ctx, input) {
94
106
  return requireClientMethod(this.client, 'updateClinicalSection')(ctx, input);
@@ -1,8 +1,8 @@
1
1
  import type { DeviceAppType } from 'gdc-common-utils-ts/constants/device';
2
- import { type ClinicalSectionUpdateCommunicationInput, type ClinicalUpdateCommunicationInput, type ClinicalSummaryReadResult, type ClinicalSummaryRequestInput } from 'gdc-sdk-core-ts';
2
+ import { type ClinicalSectionUpdateCommunicationInput, type ClinicalUpdateCommunicationInput, type ClinicalSummaryReadResult, type ClinicalSummaryRequestInput, type PermissionRequestCommunicationInput } 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
- import type { BundleSearchQuery, CommMsgExtendedCommunicationOutboxJob, CommunicationOutboxJob, CommunicationInput, DateRange, EmployeeSearchValue, IndividualOrganizationLifecycleInput, TransportProfile } from 'gdc-sdk-core-ts';
5
+ import type { BundleSearchQuery, CommMsgExtendedCommunicationOutboxJob, CommunicationOutboxJob, CommunicationInput, DateRange, EmployeeSearchValue, IndividualOrganizationLifecycleInput, TransportProfile, SubmitPayload } from 'gdc-sdk-core-ts';
6
6
  import type { BundleEntry, BundleJsonApi } from 'gdc-common-utils-ts/models/bundle';
7
7
  import type { SubmitAndPollResult } from './orchestration/client-port.js';
8
8
  import type { RouteContext } from './individual-onboarding.js';
@@ -232,6 +232,32 @@ export type CommunicationIngestionInput = {
232
232
  intervalMs?: number;
233
233
  };
234
234
  };
235
+ /**
236
+ * Canonical professional-to-subject permission request.
237
+ *
238
+ * This operation records a `Communication`; it never creates Consent or
239
+ * requires a SMART token. HTTP authentication and optional secure DIDComm
240
+ * transport remain concerns of the configured runtime client.
241
+ */
242
+ export type ProfessionalAccessRequestInput = Omit<PermissionRequestCommunicationInput, 'missing'> & Readonly<{
243
+ missing: Readonly<{
244
+ sections: string[];
245
+ resourceTypes: string[];
246
+ pairs?: PermissionRequestCommunicationInput['missing']['pairs'];
247
+ }>;
248
+ transportProfile?: TransportProfile;
249
+ pollOptions?: {
250
+ timeoutMs?: number;
251
+ intervalMs?: number;
252
+ };
253
+ }>;
254
+ /** Result of persisting one canonical permission-request Communication. */
255
+ export type ProfessionalAccessRequestResult = Readonly<{
256
+ thid: string;
257
+ communicationIdentifier: string;
258
+ communication: CommunicationInput;
259
+ delivery: SubmitAndPollResult;
260
+ }>;
235
261
  type ClinicalUpdateRuntimeOptions = Readonly<{
236
262
  transportProfile?: TransportProfile;
237
263
  clinicalFormat?: string;
@@ -326,6 +352,10 @@ export type CommunicationParticipantRuntimeSearchInput = {
326
352
  page?: number;
327
353
  count?: number;
328
354
  };
355
+ /** Subject/requester filters for canonical permission-request Communications. */
356
+ export type ProfessionalAccessRequestSearchInput = CommunicationParticipantRuntimeSearchInput;
357
+ /** Restricts a Communication participant search to permission requests. */
358
+ export declare function buildProfessionalAccessRequestSearchInput(input: ProfessionalAccessRequestSearchInput): CommunicationParticipantRuntimeSearchInput;
329
359
  export type ClinicalDateRange = DateRange;
330
360
  export type ClinicalBundleSearchInput = Omit<BundleSearchQuery, 'section' | 'searchParams'> & {
331
361
  section?: string | string[];
@@ -390,6 +420,10 @@ export type GrantProfessionalAccessInput = {
390
420
  consentIdentifier?: string;
391
421
  consentDate?: string;
392
422
  decision?: 'permit' | 'deny';
423
+ /** Permission-request Communication identifier or thread being answered. */
424
+ eventBasedOn?: string;
425
+ /** Canonical permission-request Communication reference. */
426
+ sourceReference?: string;
393
427
  attachmentContentType?: string;
394
428
  attachmentBase64?: string;
395
429
  dataType?: string;
@@ -406,6 +440,13 @@ export type GrantProfessionalAccessResult = {
406
440
  consentClaims: Record<string, unknown>;
407
441
  claimsCid?: string;
408
442
  };
443
+ /** Subject decision that remains correlated to the originating request. */
444
+ export type ProfessionalAccessRequestDecisionInput = Omit<GrantProfessionalAccessInput, 'eventBasedOn' | 'sourceReference'> & Readonly<{
445
+ requestThid: string;
446
+ requestCommunicationIdentifier?: string;
447
+ }>;
448
+ /** Converts one request decision into the canonical correlated Consent grant. */
449
+ export declare function buildProfessionalAccessRequestDecisionGrant(input: ProfessionalAccessRequestDecisionInput): GrantProfessionalAccessInput;
409
450
  export type RevokeProfessionalAccessInput = {
410
451
  consentClaims: Record<string, unknown>;
411
452
  periodEnd?: string;
@@ -685,6 +726,21 @@ export declare function ingestCommunicationAndUpdateIndexWithDeps(routeCtx: Rout
685
726
  intervalMs?: number;
686
727
  }) => Promise<SubmitAndPollResult>;
687
728
  }): Promise<SubmitAndPollResult>;
729
+ /**
730
+ * Builds and persists one professional access request against the subject's
731
+ * provider route. The request is deliberately independent from SMART because
732
+ * no subject consent exists yet.
733
+ */
734
+ export declare function requestProfessionalAccessWithDeps(routeCtx: RouteContext, input: ProfessionalAccessRequestInput, deps: {
735
+ individualCommunicationBatchPath: (ctx: RouteContext, pathFormatSegment: string) => string;
736
+ individualCommunicationPollPath: (ctx: RouteContext, pathFormatSegment: string) => string;
737
+ submitAndPoll: (submitPath: string, pollPath: string, payload: {
738
+ thid?: string;
739
+ } & Record<string, unknown>, pollOptions?: {
740
+ timeoutMs?: number;
741
+ intervalMs?: number;
742
+ }) => Promise<SubmitAndPollResult>;
743
+ }): Promise<ProfessionalAccessRequestResult>;
688
744
  export declare function searchCommunicationParticipantsWithDeps(routeCtx: RouteContext, input: CommunicationParticipantRuntimeSearchInput, deps: {
689
745
  communicationSearchPath: (ctx: RouteContext) => string;
690
746
  communicationSearchPollPath: (ctx: RouteContext) => string;
@@ -790,3 +846,12 @@ export declare function generateDigitalTwinFromSubjectDataWithDeps(routeCtx: Rou
790
846
  }) => Promise<SubmitAndPollResult>;
791
847
  }): Promise<SubmitAndPollResult>;
792
848
  export declare function normalizeCommunicationPathFormatSegment(raw?: string): string;
849
+ /**
850
+ * Selects only the outer employee wire representation.
851
+ *
852
+ * The BundleEditor-authored entries remain identical across transports:
853
+ * JSON-API `data[]` stays inside DIDComm, while the legacy FHIR profile maps
854
+ * those entries to standard `Bundle.entry[]`. Authorization and encryption
855
+ * remain runtime concerns rather than browser-authored payload fields.
856
+ */
857
+ export declare function prepareEmployeeLifecycleMessageForTransport(message: SubmitPayload, profile: TransportProfile): SubmitPayload;
@@ -2,10 +2,12 @@
2
2
  import { HealthcareBasicSections, ResourceTypesFhirR4 } from 'gdc-common-utils-ts/constants';
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
- import { buildCommunicationParticipantSearchBundle, buildBlockchainArtifactDocumentReference, BundleQuery, createInteroperableResourceOperationEditor, IndividualOrganizationLifecycleEditor, LicenseOfferSearchEditor, LicenseOrderSearchEditor, InteroperableLifecycleStatuses, LicenseListSearchEditor, buildLicenseIssueEntry, buildLicensePurchaseEntry, } from 'gdc-common-utils-ts';
6
- import { addFhirResourceToCommunication, createCommunicationResource, buildClinicalSummaryCommunicationJob, createClinicalSectionUpdateOutboxJob, createClinicalSummaryUpdateOutboxJob, readClinicalSummaryOperationResult, } from 'gdc-sdk-core-ts';
5
+ import { CommunicationClaim } from 'gdc-common-utils-ts/models/interoperable-claims/communication-claims';
6
+ import { BundleEditor, buildCommunicationParticipantSearchBundle, buildBlockchainArtifactDocumentReference, BundleQuery, createInteroperableResourceOperationEditor, IndividualOrganizationLifecycleEditor, LicenseOfferSearchEditor, LicenseOrderSearchEditor, InteroperableLifecycleStatuses, LicenseListSearchEditor, buildLicenseIssueEntry, buildLicensePurchaseEntry, } from 'gdc-common-utils-ts';
7
+ import { EmployeeBundleOperations, EmployeeResourceTypes, } from 'gdc-common-utils-ts/utils/employee';
8
+ import { addFhirResourceToCommunication, createCommunicationResource, buildClinicalSummaryCommunicationJob, buildPermissionRequestCommunication, createClinicalSectionUpdateOutboxJob, createClinicalSummaryUpdateOutboxJob, readClinicalSummaryOperationResult, TransportProfiles, } from 'gdc-sdk-core-ts';
7
9
  import { GwCoreLifecycleRequestMethod, GwCoreLifecycleRequestType, GwCoreLifecycleTodo, } from './constants/lifecycle.js';
8
- import { buildEmployeeBatchEntry, buildEmployeeSearchBundle, ConsentClaims, } from 'gdc-sdk-core-ts';
10
+ import { buildEmployeeSearchBundle, ConsentClaims, } from 'gdc-sdk-core-ts';
9
11
  export function buildClinicalSectionUpdateIngestion(input) {
10
12
  return {
11
13
  communicationJob: createClinicalSectionUpdateOutboxJob(input),
@@ -22,6 +24,30 @@ export function buildClinicalSummaryUpdateIngestion(input) {
22
24
  pollOptions: input.pollOptions,
23
25
  };
24
26
  }
27
+ /** Restricts a Communication participant search to permission requests. */
28
+ export function buildProfessionalAccessRequestSearchInput(input) {
29
+ return {
30
+ ...input,
31
+ searchParams: {
32
+ ...input.searchParams,
33
+ [CommunicationClaim.Category]: 'permission-request',
34
+ },
35
+ };
36
+ }
37
+ /** Converts one request decision into the canonical correlated Consent grant. */
38
+ export function buildProfessionalAccessRequestDecisionGrant(input) {
39
+ const requestThid = String(input.requestThid || '').trim();
40
+ if (!requestThid)
41
+ throw new Error('Permission request decision requires requestThid.');
42
+ const communicationIdentifier = String(input.requestCommunicationIdentifier || '').trim();
43
+ return {
44
+ ...input,
45
+ eventBasedOn: communicationIdentifier || requestThid,
46
+ sourceReference: communicationIdentifier
47
+ ? `Communication?identifier=${encodeURIComponent(communicationIdentifier)}`
48
+ : `Communication?thid=${encodeURIComponent(requestThid)}`,
49
+ };
50
+ }
25
51
  export async function createOrganizationEmployeeWithDeps(routeCtx, input, options, deps) {
26
52
  const payload = buildEmployeeLifecyclePayload({
27
53
  routeCtx,
@@ -387,6 +413,52 @@ export async function ingestCommunicationAndUpdateIndexWithDeps(routeCtx, input,
387
413
  : payload;
388
414
  return deps.submitAndPoll(deps.individualCommunicationBatchPath(routeCtx, pathFormatSegment), deps.individualCommunicationPollPath(routeCtx, pathFormatSegment), convertedPayload, input.pollOptions);
389
415
  }
416
+ /**
417
+ * Builds and persists one professional access request against the subject's
418
+ * provider route. The request is deliberately independent from SMART because
419
+ * no subject consent exists yet.
420
+ */
421
+ export async function requestProfessionalAccessWithDeps(routeCtx, input, deps) {
422
+ const subject = String(input.subject || '').trim();
423
+ const missingSections = input.missing.sections.map((value) => String(value || '').trim()).filter(Boolean);
424
+ const missingResourceTypes = input.missing.resourceTypes.map((value) => String(value || '').trim()).filter(Boolean);
425
+ const requesterTargets = [
426
+ input.requester.did,
427
+ input.requester.email,
428
+ input.requester.phone,
429
+ input.requester.organizationDid,
430
+ ].map((value) => String(value || '').trim()).filter(Boolean);
431
+ if (!subject.startsWith('did:'))
432
+ throw new Error('Professional access request requires a subject DID.');
433
+ if (requesterTargets.length === 0)
434
+ throw new Error('Professional access request requires an authenticated requester target.');
435
+ if (missingSections.length === 0 && missingResourceTypes.length === 0) {
436
+ throw new Error('Professional access request requires at least one missing permission.');
437
+ }
438
+ const thid = String(input.thid || '').trim() || `permission-request-${createRuntimeUuid()}`;
439
+ const communicationIdentifier = String(input.communicationIdentifier || '').trim()
440
+ || `urn:uuid:${createRuntimeUuid()}`;
441
+ const communication = buildPermissionRequestCommunication({
442
+ ...input,
443
+ subject,
444
+ thid,
445
+ communicationIdentifier,
446
+ missing: {
447
+ sections: missingSections,
448
+ resourceTypes: missingResourceTypes,
449
+ pairs: input.missing.pairs || [
450
+ ...missingSections.map((section) => ({ section, reason: 'missing-consent' })),
451
+ ...missingResourceTypes.map((resourceType) => ({ resourceType, reason: 'missing-consent' })),
452
+ ],
453
+ },
454
+ });
455
+ const delivery = await ingestCommunicationAndUpdateIndexWithDeps(routeCtx, {
456
+ communicationPayload: communication,
457
+ pathFormatSegment: 'r4',
458
+ pollOptions: input.pollOptions,
459
+ }, deps);
460
+ return { thid, communicationIdentifier, communication, delivery };
461
+ }
390
462
  export async function searchCommunicationParticipantsWithDeps(routeCtx, input, deps) {
391
463
  const payload = {
392
464
  thid: input.requestThid || `communication-search-${createRuntimeUuid()}`,
@@ -640,6 +712,8 @@ export async function grantProfessionalAccessWithDeps(routeCtx, input, deps) {
640
712
  consentIdentifier: input.consentIdentifier,
641
713
  consentDate: input.consentDate,
642
714
  decision: input.decision,
715
+ eventBasedOn: input.eventBasedOn,
716
+ sourceReference: input.sourceReference,
643
717
  attachmentContentType: input.attachmentContentType,
644
718
  attachmentBase64: input.attachmentBase64,
645
719
  }, {
@@ -721,6 +795,19 @@ function createRuntimeUuid() {
721
795
  }
722
796
  function buildEmployeeLifecyclePayload(input) {
723
797
  const claims = input.employeeClaims || {};
798
+ const editor = new BundleEditor()
799
+ .setBundleOperation(EmployeeBundleOperations.create)
800
+ .setAllowedResourceType(EmployeeResourceTypes.employee);
801
+ const employee = editor.newEntry(input.resourceId).asEmployee();
802
+ for (const [claim, value] of Object.entries(claims)) {
803
+ employee.setClaim(claim, value);
804
+ }
805
+ const authored = employee.doneEntry().buildJsonApi();
806
+ const data = authored.data.map((entry) => ({
807
+ ...entry,
808
+ type: input.requestType,
809
+ request: { method: input.requestMethod },
810
+ }));
724
811
  return {
725
812
  jti: `jti-${createRuntimeUuid()}`,
726
813
  iss: input.routeCtx.tenantId,
@@ -728,14 +815,31 @@ function buildEmployeeLifecyclePayload(input) {
728
815
  type: 'application/didcomm-plain+json',
729
816
  thid: `${input.thidPrefix}-${createRuntimeUuid()}`,
730
817
  body: {
731
- data: [buildEmployeeBatchEntry({
732
- type: input.requestType,
733
- method: input.requestMethod,
734
- claims,
735
- // Keep the transport-local GW profile anchor separate from the
736
- // exportable employee identifier carried in claims.
737
- resourceId: input.resourceId,
738
- })],
818
+ data,
819
+ },
820
+ };
821
+ }
822
+ /**
823
+ * Selects only the outer employee wire representation.
824
+ *
825
+ * The BundleEditor-authored entries remain identical across transports:
826
+ * JSON-API `data[]` stays inside DIDComm, while the legacy FHIR profile maps
827
+ * those entries to standard `Bundle.entry[]`. Authorization and encryption
828
+ * remain runtime concerns rather than browser-authored payload fields.
829
+ */
830
+ export function prepareEmployeeLifecycleMessageForTransport(message, profile) {
831
+ if (profile !== TransportProfiles.FhirJson)
832
+ return message;
833
+ const envelopeBody = message.body;
834
+ if (!Array.isArray(envelopeBody?.data)) {
835
+ throw new Error('Employee FHIR transport requires Bundle data entries.');
836
+ }
837
+ return {
838
+ ...message,
839
+ body: {
840
+ resourceType: ResourceTypesFhirR4.Bundle,
841
+ type: 'batch',
842
+ entry: envelopeBody.data,
739
843
  },
740
844
  };
741
845
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-sdk-node-ts",
3
- "version": "2.3.17",
3
+ "version": "2.3.19",
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.",
@@ -37,7 +37,7 @@
37
37
  "test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
38
38
  },
39
39
  "dependencies": {
40
- "gdc-common-utils-ts": "^2.3.18",
40
+ "gdc-common-utils-ts": "^2.3.21",
41
41
  "gdc-sdk-core-ts": "~2.3.14"
42
42
  },
43
43
  "devDependencies": {