gdc-sdk-node-ts 2.4.24 → 2.4.31
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 +15 -6
- package/dist/constants/lifecycle.d.ts +8 -0
- package/dist/constants/lifecycle.js +8 -0
- package/dist/device-activation.d.ts +48 -1
- package/dist/device-activation.js +157 -1
- package/dist/digital-twin.d.ts +12 -0
- package/dist/digital-twin.js +26 -4
- package/dist/host-onboarding.d.ts +7 -0
- package/dist/node-managed-wallet.d.ts +41 -1
- package/dist/node-managed-wallet.js +52 -0
- package/dist/node-runtime-client.d.ts +29 -1
- package/dist/node-runtime-client.js +92 -1
- package/dist/orchestration/client-port.d.ts +11 -1
- package/dist/orchestration/digital-twin-sdk.js +3 -1
- package/dist/orchestration/host-onboarding-sdk.d.ts +9 -3
- package/dist/orchestration/host-onboarding-sdk.js +10 -1
- package/dist/orchestration/individual-controller-sdk.d.ts +29 -3
- package/dist/orchestration/individual-controller-sdk.js +48 -2
- package/dist/orchestration/organization-controller-sdk.d.ts +19 -6
- package/dist/orchestration/organization-controller-sdk.js +27 -6
- package/dist/organization-controller-recovery.d.ts +4 -2
- package/dist/organization-controller-recovery.js +14 -8
- package/dist/organization-employee-lifecycle.d.ts +4 -0
- package/dist/organization-employee-lifecycle.js +17 -1
- package/dist/organization-license-order.d.ts +8 -3
- package/dist/resource-operations.d.ts +67 -0
- package/dist/resource-operations.js +62 -1
- package/dist/runtime-client-paths.d.ts +10 -0
- package/dist/runtime-client-paths.js +10 -0
- package/dist/server-profile-session.d.ts +32 -3
- package/dist/server-profile-session.js +21 -17
- package/package.json +1 -1
|
@@ -501,6 +501,33 @@ export type DigitalTwinGenerationInput = {
|
|
|
501
501
|
intervalMs?: number;
|
|
502
502
|
};
|
|
503
503
|
};
|
|
504
|
+
/** Subject decision controlling publication into the pseudonymous research index. */
|
|
505
|
+
export type DigitalTwinSecondaryUseConsentInput = {
|
|
506
|
+
subjectDid: string;
|
|
507
|
+
/** Organization/tenant that provides and stores the subject's index. */
|
|
508
|
+
indexProviderOrganizationDid: string;
|
|
509
|
+
decision: 'permit' | 'deny';
|
|
510
|
+
/** Server-owned FHIR Consent identifier. Never accept it from the browser. */
|
|
511
|
+
consentIdentifier: string;
|
|
512
|
+
consentDate?: string;
|
|
513
|
+
dataType?: string;
|
|
514
|
+
pollOptions?: {
|
|
515
|
+
timeoutMs?: number;
|
|
516
|
+
intervalMs?: number;
|
|
517
|
+
};
|
|
518
|
+
};
|
|
519
|
+
/** Result of enabling or disabling one subject's digital-twin publication. */
|
|
520
|
+
export type DigitalTwinSecondaryUseConsentResult = GrantProfessionalAccessResult;
|
|
521
|
+
/** Provider-offboarding command that destroys only the private subject/twin binding. */
|
|
522
|
+
export type DigitalTwinSubjectLinkPurgeInput = {
|
|
523
|
+
subjectDid: string;
|
|
524
|
+
pollOptions?: {
|
|
525
|
+
timeoutMs?: number;
|
|
526
|
+
intervalMs?: number;
|
|
527
|
+
};
|
|
528
|
+
};
|
|
529
|
+
/** Async GW result for a subject/twin binding purge. */
|
|
530
|
+
export type DigitalTwinSubjectLinkPurgeResult = SubmitAndPollResult;
|
|
504
531
|
export declare function createOrganizationEmployeeWithDeps(routeCtx: RouteContext, input: OrganizationEmployeeCreationInput, options: {
|
|
505
532
|
timeoutMs?: number;
|
|
506
533
|
intervalMs?: number;
|
|
@@ -882,6 +909,46 @@ export declare function grantProfessionalAccessWithDeps(routeCtx: RouteContext,
|
|
|
882
909
|
intervalMs?: number;
|
|
883
910
|
}) => Promise<SubmitAndPollResult>;
|
|
884
911
|
}): Promise<GrantProfessionalAccessResult>;
|
|
912
|
+
/**
|
|
913
|
+
* Enables or disables secondary research use for one subject.
|
|
914
|
+
*
|
|
915
|
+
* `permit` asks GW to build or rebuild the current pseudonymous projection;
|
|
916
|
+
* `deny` pauses later synchronization while preserving the published twin and
|
|
917
|
+
* tenant-private subject alias.
|
|
918
|
+
*/
|
|
919
|
+
export declare function setDigitalTwinSecondaryUseConsentWithDeps(routeCtx: RouteContext, input: DigitalTwinSecondaryUseConsentInput, deps: {
|
|
920
|
+
buildConsentClaimsWithCid: (input: GrantProfessionalAccessInput, options?: {
|
|
921
|
+
consentIdentifierFactory: () => string;
|
|
922
|
+
}) => {
|
|
923
|
+
actorIdentifier: string;
|
|
924
|
+
subjectIdentifier: string;
|
|
925
|
+
consentClaims: Record<string, unknown>;
|
|
926
|
+
claimsCid?: string;
|
|
927
|
+
};
|
|
928
|
+
individualConsentR4BatchPath: (ctx: RouteContext) => string;
|
|
929
|
+
individualConsentR4PollPath: (ctx: RouteContext) => string;
|
|
930
|
+
submitAndPoll: (submitPath: string, pollPath: string, payload: {
|
|
931
|
+
thid?: string;
|
|
932
|
+
} & Record<string, unknown>, pollOptions?: {
|
|
933
|
+
timeoutMs?: number;
|
|
934
|
+
intervalMs?: number;
|
|
935
|
+
}) => Promise<SubmitAndPollResult>;
|
|
936
|
+
}): Promise<DigitalTwinSecondaryUseConsentResult>;
|
|
937
|
+
/**
|
|
938
|
+
* Removes the index provider's private individual-to-twin correspondence.
|
|
939
|
+
* The anonymous twin is intentionally not deleted. A later enrollment gets a
|
|
940
|
+
* new UUID and cannot reconnect the detached twin to the individual.
|
|
941
|
+
*/
|
|
942
|
+
export declare function purgeDigitalTwinSubjectLinkWithDeps(routeCtx: RouteContext, input: DigitalTwinSubjectLinkPurgeInput, deps: {
|
|
943
|
+
individualResearchSubjectPurgePath: (ctx: RouteContext) => string;
|
|
944
|
+
individualResearchSubjectPurgePollPath: (ctx: RouteContext) => string;
|
|
945
|
+
submitAndPoll: (submitPath: string, pollPath: string, payload: {
|
|
946
|
+
thid?: string;
|
|
947
|
+
} & Record<string, unknown>, pollOptions?: {
|
|
948
|
+
timeoutMs?: number;
|
|
949
|
+
intervalMs?: number;
|
|
950
|
+
}) => Promise<SubmitAndPollResult>;
|
|
951
|
+
}): Promise<DigitalTwinSubjectLinkPurgeResult>;
|
|
885
952
|
export declare function revokeProfessionalAccessWithDeps(routeCtx: RouteContext, input: RevokeProfessionalAccessInput, deps: {
|
|
886
953
|
individualConsentR4BatchPath: (ctx: RouteContext) => string;
|
|
887
954
|
individualConsentR4PollPath: (ctx: RouteContext) => string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
import { HealthcareBasicSections, ResourceTypesFhirR4 } from 'gdc-common-utils-ts/constants';
|
|
2
|
+
import { HealthcareBasicSections, HealthcareConsentPurposes, ResourceTypesFhirR4, ServiceCapability, } 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
5
|
import { CommunicationClaim } from 'gdc-common-utils-ts/models/interoperable-claims/communication-claims';
|
|
@@ -9,6 +9,8 @@ import { DeviceAppTypes, DeviceUserClasses } from 'gdc-common-utils-ts/constants
|
|
|
9
9
|
import { addFhirResourceToCommunication, createCommunicationResource, buildClinicalSummaryCommunicationJob, buildPermissionRequestCommunication, createClinicalSectionUpdateOutboxJob, createClinicalSummaryUpdateOutboxJob, readClinicalSummaryOperationResult, TransportProfiles, } from 'gdc-sdk-core-ts';
|
|
10
10
|
import { GwCoreLifecycleRequestMethod, GwCoreLifecycleRequestType, GwCoreLifecycleTodo, } from './constants/lifecycle.js';
|
|
11
11
|
import { buildEmployeeSearchBundle, ConsentClaims, } from 'gdc-sdk-core-ts';
|
|
12
|
+
import { ClaimConsent } from 'gdc-common-utils-ts/models/consent-rule';
|
|
13
|
+
import { assignCidToClaimsId } from 'gdc-common-utils-ts/utils/fhir-cid';
|
|
12
14
|
export function buildClinicalSectionUpdateIngestion(input) {
|
|
13
15
|
return {
|
|
14
16
|
communicationJob: createClinicalSectionUpdateOutboxJob(input),
|
|
@@ -801,6 +803,65 @@ export async function grantProfessionalAccessWithDeps(routeCtx, input, deps) {
|
|
|
801
803
|
claimsCid: built.claimsCid,
|
|
802
804
|
};
|
|
803
805
|
}
|
|
806
|
+
/**
|
|
807
|
+
* Enables or disables secondary research use for one subject.
|
|
808
|
+
*
|
|
809
|
+
* `permit` asks GW to build or rebuild the current pseudonymous projection;
|
|
810
|
+
* `deny` pauses later synchronization while preserving the published twin and
|
|
811
|
+
* tenant-private subject alias.
|
|
812
|
+
*/
|
|
813
|
+
export async function setDigitalTwinSecondaryUseConsentWithDeps(routeCtx, input, deps) {
|
|
814
|
+
if (!String(input.consentIdentifier || '').trim()) {
|
|
815
|
+
throw new Error('consentIdentifier is required for idempotent digital-twin consent updates.');
|
|
816
|
+
}
|
|
817
|
+
const indexProviderOrganizationDid = String(input.indexProviderOrganizationDid || '').trim();
|
|
818
|
+
if (!indexProviderOrganizationDid) {
|
|
819
|
+
throw new Error('indexProviderOrganizationDid is required.');
|
|
820
|
+
}
|
|
821
|
+
const buildFhirConsentClaimsWithoutLegacyAttachment = (consentInput, options) => {
|
|
822
|
+
const built = deps.buildConsentClaimsWithCid(consentInput, options);
|
|
823
|
+
const claims = { ...built.consentClaims };
|
|
824
|
+
delete claims[ClaimConsent.attachmentContentType];
|
|
825
|
+
delete claims[ClaimConsent.attachmentData];
|
|
826
|
+
const context = String(claims['@context'] || '').trim();
|
|
827
|
+
if (context) {
|
|
828
|
+
delete claims[`${context}.${ClaimConsent.attachmentContentType}`];
|
|
829
|
+
delete claims[`${context}.${ClaimConsent.attachmentData}`];
|
|
830
|
+
}
|
|
831
|
+
const assigned = assignCidToClaimsId(claims);
|
|
832
|
+
return { ...built, consentClaims: assigned.claims, claimsCid: assigned.cid };
|
|
833
|
+
};
|
|
834
|
+
return grantProfessionalAccessWithDeps(routeCtx, {
|
|
835
|
+
subjectDid: input.subjectDid,
|
|
836
|
+
actorId: indexProviderOrganizationDid,
|
|
837
|
+
actorRole: '*',
|
|
838
|
+
purpose: HealthcareConsentPurposes.Research,
|
|
839
|
+
actions: [ServiceCapability.DigitalTwinReader],
|
|
840
|
+
decision: input.decision,
|
|
841
|
+
consentIdentifier: input.consentIdentifier,
|
|
842
|
+
consentDate: input.consentDate,
|
|
843
|
+
dataType: input.dataType,
|
|
844
|
+
pollOptions: input.pollOptions,
|
|
845
|
+
}, { ...deps, buildConsentClaimsWithCid: buildFhirConsentClaimsWithoutLegacyAttachment });
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Removes the index provider's private individual-to-twin correspondence.
|
|
849
|
+
* The anonymous twin is intentionally not deleted. A later enrollment gets a
|
|
850
|
+
* new UUID and cannot reconnect the detached twin to the individual.
|
|
851
|
+
*/
|
|
852
|
+
export async function purgeDigitalTwinSubjectLinkWithDeps(routeCtx, input, deps) {
|
|
853
|
+
const subjectDid = String(input.subjectDid || '').trim();
|
|
854
|
+
if (!subjectDid)
|
|
855
|
+
throw new Error('subjectDid is required.');
|
|
856
|
+
const thid = `digital-twin-link-purge-${createRuntimeUuid()}`;
|
|
857
|
+
return deps.submitAndPoll(deps.individualResearchSubjectPurgePath(routeCtx), deps.individualResearchSubjectPurgePollPath(routeCtx), {
|
|
858
|
+
thid,
|
|
859
|
+
body: {
|
|
860
|
+
resourceType: 'Parameters',
|
|
861
|
+
parameter: [{ name: 'subject', valueString: subjectDid }],
|
|
862
|
+
},
|
|
863
|
+
}, input.pollOptions);
|
|
864
|
+
}
|
|
804
865
|
export async function revokeProfessionalAccessWithDeps(routeCtx, input, deps) {
|
|
805
866
|
const revokedClaims = ConsentClaims
|
|
806
867
|
.fromClaims(input.consentClaims)
|
|
@@ -22,8 +22,16 @@ export declare class RuntimeClientPaths {
|
|
|
22
22
|
hostRegistryOrganizationActivatePollPath(ctx?: HostRouteContext): string;
|
|
23
23
|
hostRegistryOrganizationDisablePath(ctx?: HostRouteContext): string;
|
|
24
24
|
hostRegistryOrganizationDisablePollPath(ctx?: HostRouteContext): string;
|
|
25
|
+
hostRegistryOrganizationEnablePath(ctx?: HostRouteContext): string;
|
|
26
|
+
hostRegistryOrganizationEnablePollPath(ctx?: HostRouteContext): string;
|
|
25
27
|
hostRegistryOrganizationPurgePath(ctx?: HostRouteContext): string;
|
|
26
28
|
hostRegistryOrganizationPurgePollPath(ctx?: HostRouteContext): string;
|
|
29
|
+
hostRegistryOrganizationStatusPath(ctx?: HostRouteContext): string;
|
|
30
|
+
hostRegistryOrganizationStatusPollPath(ctx?: HostRouteContext): string;
|
|
31
|
+
hostRegistryOrganizationDisableDescendantsPath(ctx?: HostRouteContext): string;
|
|
32
|
+
hostRegistryOrganizationDisableDescendantsPollPath(ctx?: HostRouteContext): string;
|
|
33
|
+
hostRegistryOrganizationPurgeDescendantsPath(ctx?: HostRouteContext): string;
|
|
34
|
+
hostRegistryOrganizationPurgeDescendantsPollPath(ctx?: HostRouteContext): string;
|
|
27
35
|
hostRegistryOrderBatchPath(ctx?: HostRouteContext): string;
|
|
28
36
|
hostRegistryOrderPollPath(ctx?: HostRouteContext): string;
|
|
29
37
|
employeeBatchPath(ctx?: RouteContext): string;
|
|
@@ -75,6 +83,8 @@ export declare class RuntimeClientPaths {
|
|
|
75
83
|
individualRelatedPersonPurgePollPath(ctx?: RouteContext): string;
|
|
76
84
|
individualConsentR4BatchPath(ctx: RouteContext): string;
|
|
77
85
|
individualConsentR4PollPath(ctx: RouteContext): string;
|
|
86
|
+
individualResearchSubjectPurgePath(ctx: RouteContext): string;
|
|
87
|
+
individualResearchSubjectPurgePollPath(ctx: RouteContext): string;
|
|
78
88
|
individualCommunicationBatchPath(ctx: RouteContext, format: string): string;
|
|
79
89
|
individualCommunicationPollPath(ctx: RouteContext, format: string): string;
|
|
80
90
|
individualCommunicationSearchPath(ctx: RouteContext): string;
|
|
@@ -36,8 +36,16 @@ export class RuntimeClientPaths {
|
|
|
36
36
|
hostRegistryOrganizationActivatePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', '_activate-response'); }
|
|
37
37
|
hostRegistryOrganizationDisablePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Disable); }
|
|
38
38
|
hostRegistryOrganizationDisablePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', `${GwCoreLifecycleAction.Disable}-response`); }
|
|
39
|
+
hostRegistryOrganizationEnablePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Enable); }
|
|
40
|
+
hostRegistryOrganizationEnablePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', `${GwCoreLifecycleAction.Enable}-response`); }
|
|
39
41
|
hostRegistryOrganizationPurgePath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Purge); }
|
|
40
42
|
hostRegistryOrganizationPurgePollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', `${GwCoreLifecycleAction.Purge}-response`); }
|
|
43
|
+
hostRegistryOrganizationStatusPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.Status); }
|
|
44
|
+
hostRegistryOrganizationStatusPollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', `${GwCoreLifecycleAction.Status}-response`); }
|
|
45
|
+
hostRegistryOrganizationDisableDescendantsPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.DisableDescendants); }
|
|
46
|
+
hostRegistryOrganizationDisableDescendantsPollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', `${GwCoreLifecycleAction.DisableDescendants}-response`); }
|
|
47
|
+
hostRegistryOrganizationPurgeDescendantsPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', GwCoreLifecycleAction.PurgeDescendants); }
|
|
48
|
+
hostRegistryOrganizationPurgeDescendantsPollPath(ctx) { return this.hostRegistryPath(ctx, 'Organization', `${GwCoreLifecycleAction.PurgeDescendants}-response`); }
|
|
41
49
|
hostRegistryOrderBatchPath(ctx) { return this.hostRegistryPath(ctx, 'Order', '_batch'); }
|
|
42
50
|
hostRegistryOrderPollPath(ctx) { return this.hostRegistryPath(ctx, 'Order', '_batch-response'); }
|
|
43
51
|
employeeBatchPath(ctx) { return this.v1Path(ctx, 'entity', 'org.schema', 'Employee', GwCoreLifecycleAction.Batch); }
|
|
@@ -89,6 +97,8 @@ export class RuntimeClientPaths {
|
|
|
89
97
|
individualRelatedPersonPurgePollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'RelatedPerson', '_purge-response'); }
|
|
90
98
|
individualConsentR4BatchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Consent', '_batch'); }
|
|
91
99
|
individualConsentR4PollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Consent', '_batch-response'); }
|
|
100
|
+
individualResearchSubjectPurgePath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'ResearchSubject', '_purge'); }
|
|
101
|
+
individualResearchSubjectPurgePollPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'ResearchSubject', '_purge-response'); }
|
|
92
102
|
individualCommunicationBatchPath(ctx, format) { return this.v1Path(ctx, 'individual', format, 'Communication', '_batch'); }
|
|
93
103
|
individualCommunicationPollPath(ctx, format) { return this.v1Path(ctx, 'individual', format, 'Communication', '_batch-response'); }
|
|
94
104
|
individualCommunicationSearchPath(ctx) { return this.v1Path(ctx, 'individual', 'org.hl7.fhir.r4', 'Communication', '_search'); }
|
|
@@ -57,24 +57,53 @@ export type ServerProfileStore = Readonly<{
|
|
|
57
57
|
deleteSession(sessionId: string): Promise<void>;
|
|
58
58
|
}>;
|
|
59
59
|
export type ServerProfileEnrollmentInput = Readonly<{
|
|
60
|
+
/** Stable confidential id of the authenticated portal account that owns and lists this profile. */
|
|
60
61
|
ownerId: string;
|
|
62
|
+
/** Stable local id of this wallet/profile record. This is not the DCR `client_id`. */
|
|
61
63
|
profileId: string;
|
|
64
|
+
/** SDK capability family being enrolled, for example an organization controller or employee. */
|
|
62
65
|
actorKind: ActorKind;
|
|
66
|
+
/** Authorization semantics already granted to the profile; never take this from an untrusted UI field. */
|
|
63
67
|
actorMode: ServerActorMode;
|
|
68
|
+
/** Exact role/controller DID used by the actor proof, including the VP issuer when a VP is supplied. */
|
|
64
69
|
actorDid: string;
|
|
70
|
+
/** DID represented by the managed wallet. It may equal `actorDid`, as in a controller enrollment. */
|
|
65
71
|
profileDid: string;
|
|
72
|
+
/** Organization/provider DID whose configured route and policies this profile will use. */
|
|
66
73
|
providerDid: string;
|
|
74
|
+
/** Server-owned tenant, jurisdiction and sector routing context. */
|
|
67
75
|
routeContext: RouteContext;
|
|
76
|
+
/** Server-derived subject authorization boundary; never accept arbitrary browser-selected DIDs here. */
|
|
68
77
|
allowedSubjectDids: string[];
|
|
78
|
+
/**
|
|
79
|
+
* Unlock secret for the locally protected wallet seed. It is neither sent
|
|
80
|
+
* to GW nor persisted by the SDK. The integrating product decides whether
|
|
81
|
+
* it is user-entered or a separately stored, high-entropy per-profile BFF
|
|
82
|
+
* secret; it must never be logged or reused as one shared deployment PIN.
|
|
83
|
+
*/
|
|
69
84
|
pin: string;
|
|
85
|
+
/**
|
|
86
|
+
* Signed OIDC `id_token` used by GW to bind the activation code to an
|
|
87
|
+
* authenticated account/email. Its issuer, audience, signature `kid` and
|
|
88
|
+
* public JWKS must be trusted by GW. A controller VP cannot replace it.
|
|
89
|
+
*/
|
|
70
90
|
idToken: string;
|
|
91
|
+
/** One-time code returned by the completed organization flow or employee `License/_issue`. */
|
|
71
92
|
activationCode: string;
|
|
72
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Optional explicit installation identity. Normally omit it so the SDK
|
|
95
|
+
* derives the identity from the wallet key it creates for this profile.
|
|
96
|
+
*/
|
|
73
97
|
clientInstanceId?: string;
|
|
98
|
+
/** Signed actor/controller VP protected with the profile for later proof and session operations. */
|
|
74
99
|
vpToken: string;
|
|
75
|
-
/**
|
|
100
|
+
/** Redirect URIs owned by this portal/app installation. */
|
|
101
|
+
redirectUris?: string[];
|
|
102
|
+
/** Human-readable portal/app name. */
|
|
103
|
+
clientName?: string;
|
|
104
|
+
/** @deprecated Use `redirectUris`; OpenID metadata is authored internally. */
|
|
76
105
|
dcrRedirectUris?: string[];
|
|
77
|
-
/**
|
|
106
|
+
/** @deprecated Use `clientName`; OpenID metadata is authored internally. */
|
|
78
107
|
dcrClientName?: string;
|
|
79
108
|
/**
|
|
80
109
|
* Optional server-only recovery seed. It must be 32 bytes encoded as
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
|
-
import { IdentityDcrMetadataFields, IdentityDeviceInfoFields } from 'gdc-common-utils-ts/constants/identity-auth';
|
|
4
3
|
import { ActorKinds } from 'gdc-common-utils-ts/constants/actor-session';
|
|
5
4
|
import { TransportProfiles, } from 'gdc-sdk-core-ts';
|
|
6
5
|
import { NodeManagedWallet } from './node-managed-wallet.js';
|
|
7
6
|
import { NodeHttpClient } from './node-runtime-client.js';
|
|
8
7
|
import { buildIdentityOpenIdSmartTokenPath } from './runtime-paths.js';
|
|
8
|
+
import { createProfileDeviceActivationRequest } from './device-activation.js';
|
|
9
9
|
import { ProfilePinRejectedError, openServerProfileSecret, protectServerProfileSecret, } from './server-profile-protection.js';
|
|
10
10
|
/**
|
|
11
11
|
* Coordinates device registration, two-factor profile protection and SMART sessions.
|
|
@@ -36,23 +36,26 @@ export class ServerProfileSessionManager {
|
|
|
36
36
|
const storagePublicJwk = publicKeys.find((entry) => entry.purpose === 'document-at-rest')?.publicJwk;
|
|
37
37
|
if (!storagePublicJwk)
|
|
38
38
|
throw new Error('Server profile enrollment requires a document-at-rest ML-KEM key.');
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const idToken = String(input.idToken || '').trim();
|
|
40
|
+
if (!idToken)
|
|
41
|
+
throw new Error('Profile enrollment requires a signed OIDC idToken for account/email binding.');
|
|
42
|
+
const client = this.createClient(input.routeContext, idToken);
|
|
43
|
+
const redirectUris = input.redirectUris || input.dcrRedirectUris || [];
|
|
44
|
+
const clientName = String(input.clientName || input.dcrClientName || '').trim();
|
|
45
|
+
const activationRequest = createProfileDeviceActivationRequest({
|
|
42
46
|
activationCode: input.activationCode,
|
|
43
|
-
idToken
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
47
|
+
idToken,
|
|
48
|
+
...input.routeContext,
|
|
49
|
+
})
|
|
50
|
+
.setClientInstanceId(clientInstanceId)
|
|
51
|
+
.setClientName(clientName)
|
|
52
|
+
.setApplicationType('web')
|
|
53
|
+
.setRedirectUris(redirectUris)
|
|
54
|
+
.setPublicJwks(publicKeys.filter((entry) => entry.purpose !== 'document-at-rest').map((entry) => entry.publicJwk))
|
|
55
|
+
.setActorDid(input.actorDid)
|
|
56
|
+
.setProfileDid(input.profileDid)
|
|
57
|
+
.build();
|
|
58
|
+
const activation = await client.activateProfileDeviceWithActivationRequest(activationRequest);
|
|
56
59
|
const dcrBody = terminalBody(activation.dcr.poll.body);
|
|
57
60
|
const clientId = findText(dcrBody, ['client_id', 'clientId']);
|
|
58
61
|
if (!clientId)
|
|
@@ -357,6 +360,7 @@ function requireEnrollment(input) {
|
|
|
357
360
|
profileDid: input.profileDid,
|
|
358
361
|
providerDid: input.providerDid,
|
|
359
362
|
activationCode: input.activationCode,
|
|
363
|
+
idToken: input.idToken,
|
|
360
364
|
vpToken: input.vpToken,
|
|
361
365
|
}))
|
|
362
366
|
if (!String(value || '').trim())
|