gdc-sdk-node-ts 2.6.5 → 2.6.7

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
@@ -699,7 +699,9 @@ modules below.
699
699
  - draft/outbox helpers
700
700
  - document facade helpers
701
701
  - `cloneImportedClinicalDocumentForDemo(...)` for an explicit editable demo
702
- copy owned by an authenticated profile `actorDid`
702
+ copy owned by an authenticated profile `actorDid`; direct summary updates
703
+ use that same value as `sender` and the real hosted provider-tenant DID as
704
+ `recipient`, never a portal alias
703
705
  - vital-sign helpers
704
706
 
705
707
  ### Node runtime client
@@ -34,11 +34,11 @@ export async function listAuthorizedIndividualSubjectsWithDeps(routeContext, inp
34
34
  data: [{
35
35
  type: 'Family-search-v1.0',
36
36
  request: { method: 'POST' },
37
- meta: { claims: {
38
- '@context': SCHEMA_CONTEXT,
39
- ...(email ? { [CLAIM_ORGANIZATION_OWNER_EMAIL]: email } : {}),
40
- ...(telephone ? { [CLAIM_ORGANIZATION_OWNER_TELEPHONE]: telephone } : {}),
41
- } },
37
+ resource: { meta: { claims: {
38
+ '@context': SCHEMA_CONTEXT,
39
+ ...(email ? { [CLAIM_ORGANIZATION_OWNER_EMAIL]: email } : {}),
40
+ ...(telephone ? { [CLAIM_ORGANIZATION_OWNER_TELEPHONE]: telephone } : {}),
41
+ } } },
42
42
  }],
43
43
  },
44
44
  }, input.pollOptions);
@@ -58,7 +58,7 @@ export async function listAuthorizedIndividualSubjectsWithDeps(routeContext, inp
58
58
  type: 'batch',
59
59
  data: [{
60
60
  request: { method: 'POST' },
61
- meta: { status: 'active', claims: licenseClaims },
61
+ resource: { meta: { status: 'active', claims: licenseClaims } },
62
62
  }],
63
63
  },
64
64
  }, input.pollOptions);
@@ -76,7 +76,7 @@ export async function listAuthorizedIndividualSubjectsWithDeps(routeContext, inp
76
76
  data: [{
77
77
  type: 'Family-search-v1.0',
78
78
  request: { method: 'POST' },
79
- meta: { claims: organizationClaims },
79
+ resource: { meta: { claims: organizationClaims } },
80
80
  }],
81
81
  },
82
82
  }, input.pollOptions);
@@ -155,7 +155,7 @@ function readAcceptedLicenses(result) {
155
155
  }
156
156
  function readFirstClaims(result) {
157
157
  const entry = readData(result)[0];
158
- const claims = entry?.meta?.claims || entry?.resource?.meta?.claims;
158
+ const claims = entry?.resource?.meta?.claims || entry?.meta?.claims;
159
159
  return claims && typeof claims === 'object' ? claims : {};
160
160
  }
161
161
  function readData(result) {
@@ -50,16 +50,19 @@ export type BackendLoadedActorProfile = LoadedActorProfile & {
50
50
  };
51
51
  export type BackendIndividualControllerProfile = {
52
52
  profile: BackendLoadedActorProfile;
53
+ /** Loaded actor session; its `actorDid` is the operational DID to use as a direct clinical sender. */
53
54
  session: ActorSession;
54
55
  sdk: IndividualControllerSdk;
55
56
  };
56
57
  export type BackendPersonalProfile = {
57
58
  profile: BackendLoadedActorProfile;
59
+ /** Loaded actor session; its `actorDid` is the operational DID to use as a direct clinical sender. */
58
60
  session: ActorSession;
59
61
  sdk: PersonalSdk;
60
62
  };
61
63
  export type BackendIndividualMemberProfile = {
62
64
  profile: BackendLoadedActorProfile;
65
+ /** Loaded caregiver/member session; its `actorDid` is the operational DID for that relationship role. */
63
66
  session: ActorSession;
64
67
  sdk: IndividualMemberSdk;
65
68
  };
@@ -70,6 +73,7 @@ export type BackendOrganizationControllerProfile = {
70
73
  };
71
74
  export type BackendProfessionalProfile = {
72
75
  profile: BackendLoadedActorProfile;
76
+ /** Loaded professional session; its `actorDid` is the operational professional DID. */
73
77
  session: ActorSession;
74
78
  sdk: ProfessionalSdk;
75
79
  };
@@ -234,12 +234,13 @@ export async function searchDigitalTwinsWithDeps(ctx, input, deps) {
234
234
  ? {
235
235
  data: [{
236
236
  type: `${resourceType}-search-request-v1.0`,
237
- resource: { resourceType: 'Parameters', parameter: parameters },
238
- meta: {
239
- claims: Object.fromEntries([
240
- ['@context', format],
241
- ...parameters.map((parameter) => [parameter.name, parameter.valueString || parameter.valueDate || '']),
242
- ]),
237
+ resource: {
238
+ resourceType: 'Parameters',
239
+ parameter: parameters,
240
+ meta: { claims: Object.fromEntries([
241
+ ['@context', format],
242
+ ...parameters.map((parameter) => [parameter.name, parameter.valueString || parameter.valueDate || '']),
243
+ ]) },
243
244
  },
244
245
  }],
245
246
  }
@@ -35,7 +35,6 @@ export async function searchFamilyOrganizationWithDeps(deps) {
35
35
  body: {
36
36
  data: [{
37
37
  type: 'Family-search-v1.0',
38
- meta: { claims },
39
38
  resource: { meta: { claims } },
40
39
  }],
41
40
  },
@@ -27,7 +27,6 @@ export async function confirmIndividualOrganizationOrderWithDeps(deps) {
27
27
  body: {
28
28
  data: [{
29
29
  type: 'Family-order-request-v1.0',
30
- meta: { claims: orderClaims },
31
30
  resource: { meta: { claims: orderClaims } },
32
31
  }],
33
32
  },
@@ -54,7 +54,6 @@ export async function startIndividualOrganizationWithDeps(deps) {
54
54
  body: {
55
55
  data: [{
56
56
  type: GwCoreLifecycleRequestType.IndividualOrganizationRegistration,
57
- meta: { claims },
58
57
  resource: { meta: { claims } },
59
58
  }],
60
59
  },
@@ -523,6 +523,9 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
523
523
  *
524
524
  * The attached payload must be `Bundle.type=document` with `Composition` in
525
525
  * `entry[0]`; its `section[].entry[]` references delimit the updated data.
526
+ * Direct callers pass the authenticated profile `actorDid` as `sender` and
527
+ * the real hosted provider-tenant DID as `recipient`. A stable multibase URN
528
+ * or portal DID/alias is never the authenticated clinical actor.
526
529
  */
527
530
  updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<SubmitAndPollResult>;
528
531
  /**
@@ -1020,6 +1020,9 @@ export class HttpRuntimeClient {
1020
1020
  *
1021
1021
  * The attached payload must be `Bundle.type=document` with `Composition` in
1022
1022
  * `entry[0]`; its `section[].entry[]` references delimit the updated data.
1023
+ * Direct callers pass the authenticated profile `actorDid` as `sender` and
1024
+ * the real hosted provider-tenant DID as `recipient`. A stable multibase URN
1025
+ * or portal DID/alias is never the authenticated clinical actor.
1023
1026
  */
1024
1027
  async updateClinicalSummary(ctx, input) {
1025
1028
  return this.ingestCommunicationAndUpdateIndex(ctx, buildClinicalSummaryUpdateIngestion(input));
@@ -107,7 +107,11 @@ export declare class IndividualControllerSdk {
107
107
  * DELETE entries contain no resource body.
108
108
  */
109
109
  updateClinicalSection(ctx: RouteContext, input: ClinicalSectionUpdateInput): Promise<SubmitAndPollResult>;
110
- /** Updates the multi-section summary through a Composition-first document. */
110
+ /**
111
+ * Updates the multi-section summary through a Composition-first document.
112
+ * On a direct call, use the authenticated profile `actorDid` as `sender` and
113
+ * the real hosted provider-tenant DID as `recipient`.
114
+ */
111
115
  updateClinicalSummary(ctx: RouteContext, input: ClinicalSummaryUpdateInput): Promise<SubmitAndPollResult>;
112
116
  /**
113
117
  * Reads the subject's available clinical document through
@@ -158,7 +158,11 @@ export class IndividualControllerSdk {
158
158
  assertFacadeCapability(this.capabilities, ActorCapabilities.IndividualIngestCommunication, ActorKinds.IndividualController, 'updateClinicalSection');
159
159
  return requireClientMethod(this.client, 'updateClinicalSection')(ctx, input);
160
160
  }
161
- /** Updates the multi-section summary through a Composition-first document. */
161
+ /**
162
+ * Updates the multi-section summary through a Composition-first document.
163
+ * On a direct call, use the authenticated profile `actorDid` as `sender` and
164
+ * the real hosted provider-tenant DID as `recipient`.
165
+ */
162
166
  updateClinicalSummary(ctx, input) {
163
167
  assertFacadeCapability(this.capabilities, ActorCapabilities.IndividualIngestCommunication, ActorKinds.IndividualController, 'updateClinicalSummary');
164
168
  return requireClientMethod(this.client, 'updateClinicalSummary')(ctx, input);
@@ -68,7 +68,10 @@ export const recoverOrganizationControllerWithIssueWithDeps = recoverOrganizatio
68
68
  export function readLegalOrganizationCredentialReissuanceActivationCode(result) {
69
69
  const pollBody = (result?.poll?.body || {});
70
70
  for (const candidate of nestedObjects(pollBody)) {
71
- const claims = candidate.meta?.claims;
71
+ const resource = candidate.resource;
72
+ const resourceClaims = resource?.meta?.claims;
73
+ const legacyClaims = candidate.meta?.claims;
74
+ const claims = resourceClaims || legacyClaims;
72
75
  const activationCode = String(claims?.['org.schema.IndividualProduct.serialNumber'] || '').trim();
73
76
  if (activationCode)
74
77
  return activationCode;
@@ -84,8 +84,10 @@ export function readEmployeeLicenseOfferId(value) {
84
84
  for (const candidate of nestedRecords(value)) {
85
85
  if (candidate.type !== 'Employee-license-offer-v1.0')
86
86
  continue;
87
- const meta = record(candidate.meta);
88
- const claims = record(meta?.claims);
87
+ const resource = record(candidate.resource);
88
+ const resourceMeta = record(resource?.meta);
89
+ const legacyMeta = record(candidate.meta);
90
+ const claims = record(resourceMeta?.claims) || record(legacyMeta?.claims);
89
91
  const offerId = String(claims?.[ClaimsOfferSchemaorg.identifier] || '').trim();
90
92
  if (offerId)
91
93
  return offerId;
@@ -27,7 +27,6 @@ export async function confirmOrganizationLicenseOrderWithDeps(deps) {
27
27
  body: {
28
28
  data: [{
29
29
  type: deps.input.dataType || 'Organization-order-request-v1.0',
30
- meta: { claims },
31
30
  resource: { meta: { claims } },
32
31
  }],
33
32
  },
@@ -314,7 +314,14 @@ type ClinicalUpdateRuntimeOptions = Readonly<{
314
314
  * controller cannot subsequently update or delete that source-authored fact.
315
315
  */
316
316
  export type ClinicalSectionUpdateInput = ClinicalSectionUpdateCommunicationInput & ClinicalUpdateRuntimeOptions;
317
- /** Updates one complete multi-section clinical summary document. */
317
+ /**
318
+ * Updates one complete multi-section clinical summary document.
319
+ *
320
+ * For the direct call, `sender` is the authenticated profile's operational
321
+ * `actorDid`, and `recipient` is the real provider-tenant DID inside the host
322
+ * that accommodates it. Neither value is a portal alias. When the document is
323
+ * an editable demo clone, its `Composition.author` is that same `actorDid`.
324
+ */
318
325
  export type ClinicalSummaryUpdateInput = ClinicalUpdateCommunicationInput & ClinicalUpdateRuntimeOptions;
319
326
  export declare function buildClinicalSectionUpdateIngestion(input: ClinicalSectionUpdateInput): CommunicationIngestionInput;
320
327
  export declare function buildClinicalSummaryUpdateIngestion(input: ClinicalSummaryUpdateInput): CommunicationIngestionInput;
@@ -340,11 +340,11 @@ export async function transitionIndividualMemberLicenseWithDeps(routeCtx, action
340
340
  ...(input.ownerOrganizationId ? { ownerOrganizationId: input.ownerOrganizationId } : {}),
341
341
  ...(input.subjectId ? { subjectId: input.subjectId } : {}),
342
342
  ...(input.verifiedActorIdentifier ? { verifiedActorIdentifier: input.verifiedActorIdentifier } : {}),
343
- claims: {
344
- '@context': 'org.schema',
345
- 'org.schema.IndividualProduct.serialNumber': input.activationCode,
346
- },
347
343
  },
344
+ resource: { meta: { claims: {
345
+ '@context': 'org.schema',
346
+ 'org.schema.IndividualProduct.serialNumber': input.activationCode,
347
+ } } },
348
348
  request: { method: 'POST' },
349
349
  }],
350
350
  },
@@ -414,7 +414,6 @@ export async function disableIndividualMemberWithDeps(routeCtx, input, options,
414
414
  type: 'batch',
415
415
  entry: [{
416
416
  request: { method: GwCoreLifecycleRequestMethod.Post },
417
- meta: { claims },
418
417
  resource: {
419
418
  ...resource,
420
419
  ...(input.resourceId ? { id: input.resourceId } : {}),
@@ -444,7 +443,6 @@ export async function purgeIndividualMemberWithDeps(routeCtx, input, options, de
444
443
  entry: [{
445
444
  type: input.dataType || GwCoreLifecycleRequestType.IndividualMemberPurge,
446
445
  request: { method: GwCoreLifecycleRequestMethod.Post },
447
- meta: { claims },
448
446
  resource: {
449
447
  ...resource,
450
448
  ...(input.resourceId ? { id: input.resourceId } : {}),
@@ -550,7 +548,6 @@ export async function requestProfessionalAccessWithDeps(routeCtx, input, deps) {
550
548
  type: 'batch',
551
549
  data: [{
552
550
  type: 'CommMsgExtended',
553
- meta: { claims: communicationClaims },
554
551
  resource: communicationResource,
555
552
  }],
556
553
  },
@@ -701,7 +698,6 @@ export function buildBlockchainArtifactBundleFromSearchResponse(input) {
701
698
  });
702
699
  return {
703
700
  type: 'DocumentReference',
704
- meta: { claims: artifact.documentReference.meta?.claims || {} },
705
701
  resource: artifact.documentReference,
706
702
  request: {
707
703
  method: 'POST',
@@ -762,7 +758,6 @@ export async function registerBlockchainArtifactAndUpdateIndexWithDeps(routeCtx,
762
758
  type: 'batch',
763
759
  data: [{
764
760
  type: 'DocumentReference',
765
- meta: { claims: artifact.documentReference.meta?.claims || {} },
766
761
  resource: artifact.documentReference,
767
762
  request: {
768
763
  method: 'POST',
@@ -840,7 +835,6 @@ export async function grantProfessionalAccessWithDeps(routeCtx, input, deps) {
840
835
  body: {
841
836
  data: [{
842
837
  type: input.dataType || 'Consent-grant-request-v1.0',
843
- meta: { claims: built.consentClaims },
844
838
  resource: { resourceType: 'Consent', meta: { claims: built.consentClaims } },
845
839
  }],
846
840
  },
@@ -983,7 +977,6 @@ export async function revokeProfessionalAccessWithDeps(routeCtx, input, deps) {
983
977
  body: {
984
978
  data: [{
985
979
  type: input.dataType || 'Consent-grant-request-v1.0',
986
- meta: { claims: revokedClaims },
987
980
  resource: { resourceType: 'Consent', meta: { claims: revokedClaims } },
988
981
  }],
989
982
  },
@@ -65,13 +65,6 @@ export async function activateOrganizationInGatewayFromIcaProofWithDeps(input) {
65
65
  ...(input.activationInput.controller ? { controller: input.activationInput.controller } : {}),
66
66
  data: [{
67
67
  type: 'Organization-activation-request-v1.0',
68
- meta: {
69
- claims: {
70
- '@context': 'org.schema',
71
- ...serviceClaims,
72
- ...(input.activationInput.additionalClaims || {}),
73
- },
74
- },
75
68
  resource: {
76
69
  meta: {
77
70
  claims: {
@@ -1,6 +1,7 @@
1
1
  // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
2
  import { buildGwCoreTenantResourceActionPath } from 'gdc-common-utils-ts/utils/gw-core-path';
3
- import { IdentityAuthActions, IdentityAuthRouteSegments } from 'gdc-common-utils-ts/constants/identity-auth';
3
+ import { IdentityAuthActions, IdentityAuthResourceTypes, IdentityAuthRouteSegments, SmartPostDcrActions, } from 'gdc-common-utils-ts/constants/identity-auth';
4
+ import { GatewayRouteFormats, GatewayRouteSections, } from 'gdc-common-utils-ts/constants/gateway-response';
4
5
  export function buildV1Path(routeCtx, section, format, resourceType, action) {
5
6
  return buildGwCoreTenantResourceActionPath({
6
7
  tenantId: routeCtx.tenantId,
@@ -60,8 +61,8 @@ function buildIdentityAuthPath(ctx, action) {
60
61
  return `/${encodeURIComponent(IdentityAuthRouteSegments.Host)}/cds-${encodeURIComponent(ctx.jurisdiction)}/${IdentityAuthRouteSegments.Version}/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/${IdentityAuthRouteSegments.Section}/${IdentityAuthRouteSegments.Format}/${encodeURIComponent(action)}`;
61
62
  }
62
63
  export function buildIdentityOpenIdSmartTokenPath(ctx) {
63
- return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/token`;
64
+ return buildV1Path(ctx, GatewayRouteSections.Identity, GatewayRouteFormats.OpenId, IdentityAuthResourceTypes.Smart, SmartPostDcrActions.Token);
64
65
  }
65
66
  export function buildIdentityOpenIdSmartTokenPollPath(ctx) {
66
- return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/_batch-response`;
67
+ return buildV1Path(ctx, GatewayRouteSections.Identity, GatewayRouteFormats.OpenId, IdentityAuthResourceTypes.Smart, SmartPostDcrActions.TokenResponse);
67
68
  }
@@ -379,6 +379,7 @@ export declare class ServerProfileSessionManager {
379
379
  openProfessional(input: ServerProfessionalOpenInput): Promise<OpenedServerProfessional>;
380
380
  lock(ownerId: string, sessionId: string): Promise<void>;
381
381
  private createClient;
382
+ private createRegisteredProfileClient;
382
383
  private createWallet;
383
384
  /**
384
385
  * Upgrade legacy profiles deterministically after successful PIN unlock.
@@ -328,12 +328,13 @@ export class ServerProfileSessionManager {
328
328
  profile = await this.ensureRequiredStorageProfile(profile, seed);
329
329
  const walletKeyDerivationId = profile.walletKeyDerivationId || profile.profileId;
330
330
  const wallet = await this.createWallet(walletKeyDerivationId, seed);
331
+ const context = walletContext(walletKeyDerivationId);
331
332
  const smartTokenEndpoint = [
332
333
  this.options.gatewayBaseUrl.replace(/\/+$/, ''),
333
334
  buildIdentityOpenIdSmartTokenPath(profile.routeContext),
334
335
  ].join('');
335
336
  const assertion = await buildWalletClientAssertion(wallet, profile, smartTokenEndpoint, now);
336
- const token = await this.createClient(profile.routeContext, input.idToken).requestSmartToken({
337
+ const token = await this.createRegisteredProfileClient(profile, wallet, context, input.idToken).requestSmartToken({
337
338
  ...profile.routeContext,
338
339
  actorDid: profile.actorDid,
339
340
  subjectDid: input.subjectDid,
@@ -394,13 +395,14 @@ export class ServerProfileSessionManager {
394
395
  : undefined;
395
396
  const walletKeyDerivationId = profile.walletKeyDerivationId || profile.profileId;
396
397
  const wallet = await this.createWallet(walletKeyDerivationId, seed);
398
+ const context = walletContext(walletKeyDerivationId);
397
399
  const now = this.now();
398
400
  const smartTokenEndpoint = [
399
401
  this.options.gatewayBaseUrl.replace(/\/+$/, ''),
400
402
  buildIdentityOpenIdSmartTokenPath(profile.routeContext),
401
403
  ].join('');
402
404
  const assertion = await buildWalletClientAssertion(wallet, profile, smartTokenEndpoint, now);
403
- const token = await this.createClient(profile.routeContext, normalizedIdToken).requestSmartToken({
405
+ const token = await this.createRegisteredProfileClient(profile, wallet, context, normalizedIdToken).requestSmartToken({
404
406
  ...profile.routeContext,
405
407
  actorDid: profile.actorDid,
406
408
  subjectDid: session.subjectDid,
@@ -546,13 +548,11 @@ export class ServerProfileSessionManager {
546
548
  transportProfile: TransportProfiles.DidcommEncryptedForm,
547
549
  secureTransportAdapter,
548
550
  });
549
- // SMART/OpenID uses its own JSON/form protocol and must not be wrapped in
550
- // the encrypted resource transport selected for later business actions.
551
- // Professional business operations are authored by the registered employee
552
- // wallet and therefore use the encrypted DIDComm client. SMART/OpenID below
553
- // remains an independent JSON/form exchange through its dedicated method.
551
+ // Both SMART and later business operations are post-DCR profile actions.
552
+ // Strict GW therefore resolves the same registered employee wallet for the
553
+ // encrypted request and poll transport used by both facades.
554
554
  const sdk = new ProfessionalSdk(operationalClient);
555
- const smartSdk = new ProfessionalSdk(this.createClient(profile.routeContext, idToken));
555
+ const smartSdk = sdk;
556
556
  const digitalTwin = new DigitalTwinSdk(operationalClient, profile.actorDid);
557
557
  let digitalTwinAccessToken;
558
558
  const request = async (smart) => {
@@ -625,6 +625,20 @@ export class ServerProfileSessionManager {
625
625
  appInfo: this.options.appInfo,
626
626
  });
627
627
  }
628
+ createRegisteredProfileClient(profile, wallet, context, bearerToken) {
629
+ return new NodeHttpClient({
630
+ baseUrl: this.options.gatewayBaseUrl,
631
+ ctx: profile.routeContext,
632
+ bearerToken,
633
+ fetchImpl: this.options.fetchImpl,
634
+ appInfo: this.options.appInfo,
635
+ transportProfile: TransportProfiles.DidcommEncryptedForm,
636
+ secureTransportAdapter: {
637
+ pack: (message) => wallet.packForRecipientWithContext(bindOrganizationControllerTransport(message, profile), profile.providerDid, { context }),
638
+ unpack: async (jwe) => (await wallet.unpackWithContext(jwe, { context })).content,
639
+ },
640
+ });
641
+ }
628
642
  async createWallet(walletKeyDerivationId, seed) {
629
643
  const wallet = new NodeManagedWallet({ resolveRecipientJwk: this.options.resolveRecipientJwk });
630
644
  const context = walletContext(walletKeyDerivationId);
package/dist/session.d.ts CHANGED
@@ -34,6 +34,7 @@ export type DemoClinicalDocumentCloneOptions = Readonly<{
34
34
  */
35
35
  export declare class ActorSession {
36
36
  readonly actorKind: ActorKind;
37
+ /** Operational DID returned with the loaded actor profile, including its role-bearing path. */
37
38
  readonly actorDid?: string;
38
39
  readonly subjectDid?: string;
39
40
  readonly capabilities: NodeCapability[];
@@ -54,7 +55,11 @@ export declare class ActorSession {
54
55
  asProfessional(): ProfessionalSdk;
55
56
  /** Materializes the digital-twin facade for an organization employee or professional actor. */
56
57
  asDigitalTwin(): DigitalTwinSdk;
57
- /** Creates an editable demo copy owned by this session's authenticated actor DID. */
58
+ /**
59
+ * Creates an editable demo copy whose `Composition.author` is this
60
+ * authenticated profile's operational `actorDid`. The actor is never taken
61
+ * from a stable multibase URN or a DID/alias supplied by a portal.
62
+ */
58
63
  cloneImportedClinicalDocumentForDemo(bundle: Record<string, unknown>, options?: DemoClinicalDocumentCloneOptions): Record<string, any>;
59
64
  private requireClient;
60
65
  }
package/dist/session.js CHANGED
@@ -70,7 +70,11 @@ export class ActorSession {
70
70
  }
71
71
  return new DigitalTwinSdk(this.requireClient(), this.actorDid);
72
72
  }
73
- /** Creates an editable demo copy owned by this session's authenticated actor DID. */
73
+ /**
74
+ * Creates an editable demo copy whose `Composition.author` is this
75
+ * authenticated profile's operational `actorDid`. The actor is never taken
76
+ * from a stable multibase URN or a DID/alias supplied by a portal.
77
+ */
74
78
  cloneImportedClinicalDocumentForDemo(bundle, options = {}) {
75
79
  const actorDid = String(this.actorDid || '').trim();
76
80
  if (!actorDid) {
@@ -1,5 +1,7 @@
1
1
  // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
2
  import { HealthcareConsentPurposes } from 'gdc-common-utils-ts/constants';
3
+ import { IdentityAuthResourceTypes, SmartPostDcrActions, } from 'gdc-common-utils-ts/constants/identity-auth';
4
+ import { GatewayRouteFormats, GatewayRouteSections, } from 'gdc-common-utils-ts/constants/gateway-response';
3
5
  import { buildClientAssertionJwt } from 'gdc-common-utils-ts/utils/client-assertion';
4
6
  import { resolvePollOptionsFromSeconds } from './poll-options.js';
5
7
  /**
@@ -109,16 +111,19 @@ function normalizeResolvedSmartTokenEndpoint(value) {
109
111
  if (!['http:', 'https:'].includes(endpoint.protocol)) {
110
112
  throw new Error('Resolved SMART token endpoint must use HTTP(S).');
111
113
  }
112
- if (!endpoint.pathname.endsWith('/identity/openid/smart/token')) {
113
- throw new Error('Resolved SMART token endpoint must target /identity/openid/smart/token.');
114
+ if (!endpoint.pathname.endsWith(smartTokenRouteSuffix(SmartPostDcrActions.Token))) {
115
+ throw new Error(`Resolved SMART token endpoint must target ${smartTokenRouteSuffix(SmartPostDcrActions.Token)}.`);
114
116
  }
115
117
  return endpoint.toString();
116
118
  }
117
119
  function smartTokenPollEndpointFromTokenEndpoint(tokenEndpoint) {
118
120
  const endpoint = new URL(tokenEndpoint);
119
- endpoint.pathname = endpoint.pathname.replace(/\/identity\/openid\/smart\/token$/, '/identity/openid/smart/_batch-response');
121
+ endpoint.pathname = `${endpoint.pathname.slice(0, -smartTokenRouteSuffix(SmartPostDcrActions.Token).length)}${smartTokenRouteSuffix(SmartPostDcrActions.TokenResponse)}`;
120
122
  return endpoint.toString();
121
123
  }
124
+ function smartTokenRouteSuffix(action) {
125
+ return `/${GatewayRouteSections.Identity}/${GatewayRouteFormats.OpenId}/${IdentityAuthResourceTypes.Smart}/${action}`;
126
+ }
122
127
  async function resolveClientAssertion(input) {
123
128
  const explicit = String(input.clientAssertion || '').trim();
124
129
  if (explicit)
@@ -132,7 +137,10 @@ async function resolveClientAssertion(input) {
132
137
  });
133
138
  }
134
139
  function resolveTokenExchangeResult(exchange, normalizedScopes, tokenCacheKey, setTokenCache) {
135
- const exchangeBody = exchange.poll.body ?? {};
140
+ const pollBody = exchange.poll.body ?? {};
141
+ // Encrypted DIDComm returns the token in the authenticated message body;
142
+ // plain compatibility transports may still expose the token at the root.
143
+ const exchangeBody = pollBody.body || pollBody;
136
144
  const accessToken = String(exchangeBody.access_token || '').trim();
137
145
  if (exchange.poll.status >= 400 || !accessToken) {
138
146
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-sdk-node-ts",
3
- "version": "2.6.5",
3
+ "version": "2.6.7",
4
4
  "description": "Next-generation Node runtime package for the GDC SDK family",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Antifraud Services Inc.",
@@ -38,8 +38,8 @@
38
38
  "test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
39
39
  },
40
40
  "dependencies": {
41
- "gdc-common-utils-ts": "2.7.4",
42
- "gdc-sdk-core-ts": "2.4.5"
41
+ "gdc-common-utils-ts": "2.7.8",
42
+ "gdc-sdk-core-ts": "2.4.9"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^20.14.10",