gdc-sdk-node-ts 2.5.1 → 2.6.0
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/dist/device-activation.js +8 -4
- package/dist/digital-twin.d.ts +5 -3
- package/dist/digital-twin.js +71 -17
- package/dist/node-runtime-client.d.ts +5 -0
- package/dist/node-runtime-client.js +14 -3
- package/dist/orchestration/digital-twin-sdk.d.ts +3 -2
- package/dist/orchestration/digital-twin-sdk.js +3 -2
- package/dist/orchestration/individual-controller-sdk.d.ts +6 -0
- package/dist/orchestration/individual-controller-sdk.js +6 -0
- package/dist/organization-employee-lifecycle.d.ts +5 -1
- package/dist/organization-employee-lifecycle.js +5 -2
- package/dist/resource-operations.d.ts +10 -0
- package/dist/server-profile-session.js +6 -2
- package/package.json +3 -3
- package/dist/organization-registration-authorization.d.ts +0 -16
- package/dist/organization-registration-authorization.js +0 -34
|
@@ -98,8 +98,10 @@ export async function activateEmployeeDeviceWithActivationCodeWithDeps(deps) {
|
|
|
98
98
|
throw new Error('Device activation requires a stable device, software, redirect, or key identifier.');
|
|
99
99
|
const exchangePayload = {
|
|
100
100
|
thid: `exchange-${createRuntimeUuid()}`,
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
body: {
|
|
102
|
+
[IdentityAuthRequestFields.SubjectToken]: deps.input.activationCode,
|
|
103
|
+
[IdentityAuthRequestFields.ClientInstanceId]: clientInstanceId,
|
|
104
|
+
},
|
|
103
105
|
};
|
|
104
106
|
const exchange = await deps.submitAndPollWithBearerToken(deps.input.idToken, deps.identityTokenExchangePath(deps.routeCtx), deps.identityTokenExchangePollPath(deps.routeCtx), exchangePayload, deps.input.pollOptions);
|
|
105
107
|
const exchangeDiagnostics = firstFailedOperationOutcomeDiagnostic(exchange.poll.body)
|
|
@@ -122,8 +124,10 @@ export async function activateEmployeeDeviceWithActivationCodeWithDeps(deps) {
|
|
|
122
124
|
}
|
|
123
125
|
const dcrPayload = {
|
|
124
126
|
thid: `dcr-${createRuntimeUuid()}`,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
body: {
|
|
128
|
+
[IdentityAuthRequestFields.Code]: deps.input.activationCode,
|
|
129
|
+
...deps.input.dcrPayload,
|
|
130
|
+
},
|
|
127
131
|
};
|
|
128
132
|
const dcr = await deps.submitAndPollWithBearerToken(initialAccessToken, deps.identityDeviceDcrPath(deps.routeCtx), deps.identityDeviceDcrPollPath(deps.routeCtx), dcrPayload, deps.input.pollOptions);
|
|
129
133
|
return {
|
package/dist/digital-twin.d.ts
CHANGED
|
@@ -37,9 +37,11 @@ export type DigitalTwinSearchInput = {
|
|
|
37
37
|
/**
|
|
38
38
|
* One public ResearchSubject digital twin returned by search.
|
|
39
39
|
*
|
|
40
|
-
* `composition` is
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* `composition` is an SDK-only normalized view of the canonical Composition:
|
|
41
|
+
* it comes from mixed `meta.claims` in claims-first API responses or from
|
|
42
|
+
* `ResearchSubject.contained[]` in strict FHIR R4/R5. GW never emits an
|
|
43
|
+
* ad-hoc `ResearchSubject.composition` wire property. The canonical index joins
|
|
44
|
+
* the ResearchSubject to resources later returned by `$summary`.
|
|
43
45
|
*/
|
|
44
46
|
export type DigitalTwinSearchMatch = Record<string, unknown> & {
|
|
45
47
|
resourceType?: 'ResearchSubject';
|
package/dist/digital-twin.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { HealthcareDocumentTypes } from 'gdc-common-utils-ts/constants';
|
|
4
4
|
import { CompositionClaim } from 'gdc-common-utils-ts/models';
|
|
5
|
+
import { extractBundleSearchResources } from 'gdc-common-utils-ts/utils/organization-employee-lifecycle';
|
|
5
6
|
const DIGITAL_TWIN_SUBJECT_URN_UUID = /^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6
7
|
/** Returns whether a value can be used as a pseudonymous digital-twin subject. */
|
|
7
8
|
export function isDigitalTwinSubjectId(value) {
|
|
@@ -38,6 +39,62 @@ export function buildDigitalTwinSelectionIdentifier(input) {
|
|
|
38
39
|
compositionId: selectionId,
|
|
39
40
|
});
|
|
40
41
|
}
|
|
42
|
+
function asRecord(value) {
|
|
43
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
44
|
+
? value
|
|
45
|
+
: undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Normalizes the public aggregate without leaking its wire representation.
|
|
49
|
+
* Claims-first responses mix ResearchSubject and Composition flat claims in
|
|
50
|
+
* `meta.claims`; versioned FHIR responses carry the translated Composition in
|
|
51
|
+
* `contained[]`. The ad-hoc `composition` property remains read-only legacy.
|
|
52
|
+
*/
|
|
53
|
+
function normalizeDigitalTwinSearchMatch(resource) {
|
|
54
|
+
const metaClaims = asRecord(asRecord(resource.meta)?.claims);
|
|
55
|
+
const containedComposition = Array.isArray(resource.contained)
|
|
56
|
+
? resource.contained.map(asRecord).find((candidate) => candidate?.resourceType === 'Composition')
|
|
57
|
+
: undefined;
|
|
58
|
+
const legacyComposition = asRecord(resource.composition);
|
|
59
|
+
const legacyCompositionClaims = asRecord(asRecord(legacyComposition?.meta)?.claims);
|
|
60
|
+
const containedSubject = asRecord(containedComposition?.subject)?.reference;
|
|
61
|
+
const subject = resource[CompositionClaim.Subject]
|
|
62
|
+
?? metaClaims?.[CompositionClaim.Subject]
|
|
63
|
+
?? containedSubject
|
|
64
|
+
?? legacyComposition?.[CompositionClaim.Subject]
|
|
65
|
+
?? legacyCompositionClaims?.[CompositionClaim.Subject];
|
|
66
|
+
assertDigitalTwinSubjectId(subject);
|
|
67
|
+
const composition = containedComposition
|
|
68
|
+
?? legacyComposition
|
|
69
|
+
?? (metaClaims ? { resourceType: 'Composition', meta: { claims: metaClaims } } : undefined);
|
|
70
|
+
return {
|
|
71
|
+
...resource,
|
|
72
|
+
[CompositionClaim.Subject]: subject,
|
|
73
|
+
...(composition ? { composition } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Finds the primary-document Bundle inside a direct or decoded DIDComm response. */
|
|
77
|
+
function findDigitalTwinSearchBundle(value) {
|
|
78
|
+
const pending = [value];
|
|
79
|
+
const visited = new Set();
|
|
80
|
+
while (pending.length > 0) {
|
|
81
|
+
const candidate = pending.shift();
|
|
82
|
+
if (!candidate || typeof candidate !== 'object' || visited.has(candidate))
|
|
83
|
+
continue;
|
|
84
|
+
visited.add(candidate);
|
|
85
|
+
if (Array.isArray(candidate)) {
|
|
86
|
+
pending.push(...candidate);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const record = candidate;
|
|
90
|
+
const hasEntries = Array.isArray(record.data) || Array.isArray(record.entry);
|
|
91
|
+
if (hasEntries && (record.resourceType === 'Bundle' || candidate === value)) {
|
|
92
|
+
return record;
|
|
93
|
+
}
|
|
94
|
+
pending.push(...Object.values(record));
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
41
98
|
function normalizeResearchTags(tags) {
|
|
42
99
|
if (!Array.isArray(tags) || tags.length === 0)
|
|
43
100
|
throw new Error('At least one research tag is required.');
|
|
@@ -61,24 +118,21 @@ function normalizeResearchTags(tags) {
|
|
|
61
118
|
}
|
|
62
119
|
/** Opens the GW async response and exposes the matched ResearchSubjects directly. */
|
|
63
120
|
export function readDigitalTwinSearchResult(operation) {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
?
|
|
67
|
-
: Array.isArray(
|
|
68
|
-
?
|
|
69
|
-
:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return Boolean(resource && typeof resource === 'object' && Array.isArray(resource.data));
|
|
73
|
-
});
|
|
74
|
-
if (!responseEntry?.resource || !Array.isArray(responseEntry.resource.data)) {
|
|
75
|
-
throw new Error('Digital twin search did not return a Composition result set.');
|
|
76
|
-
}
|
|
77
|
-
const matches = responseEntry.resource.data;
|
|
78
|
-
for (const match of matches) {
|
|
79
|
-
assertDigitalTwinSubjectId(match?.[CompositionClaim.Subject]);
|
|
121
|
+
const bundle = findDigitalTwinSearchBundle(operation?.poll?.body);
|
|
122
|
+
const entries = Array.isArray(bundle?.data)
|
|
123
|
+
? bundle.data
|
|
124
|
+
: Array.isArray(bundle?.entry)
|
|
125
|
+
? bundle.entry
|
|
126
|
+
: undefined;
|
|
127
|
+
if (!bundle || !entries) {
|
|
128
|
+
throw new Error('Digital twin search did not return a ResearchSubject result set.');
|
|
80
129
|
}
|
|
81
|
-
const
|
|
130
|
+
const matches = extractBundleSearchResources({ ...bundle, data: entries })
|
|
131
|
+
.map(normalizeDigitalTwinSearchMatch);
|
|
132
|
+
const legacyAggregate = entries
|
|
133
|
+
.map((entry) => entry?.resource)
|
|
134
|
+
.find((resource) => resource && typeof resource === 'object' && Array.isArray(resource.data));
|
|
135
|
+
const parsedTotal = Number(legacyAggregate?.total ?? bundle.total);
|
|
82
136
|
return {
|
|
83
137
|
total: Number.isFinite(parsedTotal) ? parsedTotal : matches.length,
|
|
84
138
|
matches,
|
|
@@ -86,6 +86,7 @@ export type NodeHttpClientOptions = HttpRuntimeClientOptions;
|
|
|
86
86
|
export declare class HttpRuntimeClient implements NodeRuntimeClient {
|
|
87
87
|
private readonly baseUrl;
|
|
88
88
|
private readonly bearerToken?;
|
|
89
|
+
private activeSmartBearerToken?;
|
|
89
90
|
private readonly runtimeVpToken?;
|
|
90
91
|
private readonly resolvedAppInfo?;
|
|
91
92
|
private readonly ctx?;
|
|
@@ -461,6 +462,10 @@ export declare class HttpRuntimeClient implements NodeRuntimeClient {
|
|
|
461
462
|
* Route details are resolved either from `input` compatibility fields
|
|
462
463
|
* (`tenantId` / `jurisdiction` / `sector`) or from
|
|
463
464
|
* the default client route context configured in the constructor.
|
|
465
|
+
* A fetched actor-scoped access token is retained by this runtime for later
|
|
466
|
+
* clinical operations. Token acquisition and renewal continue to use the
|
|
467
|
+
* original account bearer, so applications must not reconstruct the SDK or
|
|
468
|
+
* manually replace its transport after this method returns.
|
|
464
469
|
*/
|
|
465
470
|
requestSmartToken(input: SmartTokenRequestInput): Promise<SmartTokenExchangeResult>;
|
|
466
471
|
/**
|
|
@@ -33,7 +33,7 @@ export class HttpRuntimeClient {
|
|
|
33
33
|
get transportConfig() {
|
|
34
34
|
return {
|
|
35
35
|
baseUrl: this.baseUrl,
|
|
36
|
-
bearerToken: this.bearerToken,
|
|
36
|
+
bearerToken: this.activeSmartBearerToken || this.bearerToken,
|
|
37
37
|
defaultHeaders: this.defaultHeaders,
|
|
38
38
|
requestTimeoutMs: this.requestTimeoutMs,
|
|
39
39
|
httpTraceFile: this.httpTraceFile,
|
|
@@ -886,10 +886,14 @@ export class HttpRuntimeClient {
|
|
|
886
886
|
* Route details are resolved either from `input` compatibility fields
|
|
887
887
|
* (`tenantId` / `jurisdiction` / `sector`) or from
|
|
888
888
|
* the default client route context configured in the constructor.
|
|
889
|
+
* A fetched actor-scoped access token is retained by this runtime for later
|
|
890
|
+
* clinical operations. Token acquisition and renewal continue to use the
|
|
891
|
+
* original account bearer, so applications must not reconstruct the SDK or
|
|
892
|
+
* manually replace its transport after this method returns.
|
|
889
893
|
*/
|
|
890
894
|
async requestSmartToken(input) {
|
|
891
895
|
const routeCtx = this.paths.routeCtxFromInput(input);
|
|
892
|
-
|
|
896
|
+
const result = await requestSmartTokenWithDeps({
|
|
893
897
|
input,
|
|
894
898
|
routeCtx,
|
|
895
899
|
baseUrl: this.baseUrl,
|
|
@@ -900,9 +904,16 @@ export class HttpRuntimeClient {
|
|
|
900
904
|
identityOpenIdSmartTokenPath: this.paths.identityOpenIdSmartTokenPath.bind(this.paths),
|
|
901
905
|
identityOpenIdSmartTokenPollPath: this.paths.identityOpenIdSmartTokenPollPath.bind(this.paths),
|
|
902
906
|
resolveSmartTokenEndpoint: this.smartTokenEndpointResolver,
|
|
903
|
-
|
|
907
|
+
// Token acquisition and refresh remain authenticated by the original
|
|
908
|
+
// account bearer. A previously granted SMART token must not replace the
|
|
909
|
+
// OIDC proof used to request the next actor-scoped token.
|
|
910
|
+
submitAndPoll: this.submitAndPollWithBearerToken.bind(this, this.bearerToken),
|
|
904
911
|
setTokenCache: (tokenCacheKey, token) => this.tokenCache.set(tokenCacheKey, token),
|
|
905
912
|
});
|
|
913
|
+
if (result.status === 'fetched' && result.accessToken) {
|
|
914
|
+
this.activeSmartBearerToken = result.accessToken;
|
|
915
|
+
}
|
|
916
|
+
return result;
|
|
906
917
|
}
|
|
907
918
|
/**
|
|
908
919
|
* Registers any actor profile device through activation-code exchange plus
|
|
@@ -12,8 +12,9 @@ export declare class DigitalTwinSdk {
|
|
|
12
12
|
requestSmartToken(input: SmartTokenRequestInput): Promise<SmartTokenExchangeResult>;
|
|
13
13
|
/**
|
|
14
14
|
* Searches the public `ResearchSubject/_search` aggregate with FHIR
|
|
15
|
-
* Parameters.
|
|
16
|
-
*
|
|
15
|
+
* Parameters. The high-level match normalizes either mixed claims-first
|
|
16
|
+
* `meta.claims` or a versioned FHIR `contained[]` Composition. Callers never
|
|
17
|
+
* need to navigate either transport representation.
|
|
17
18
|
*
|
|
18
19
|
* MVP basic search supplies `sections`, `dateFrom`, optional `dateTo`, and
|
|
19
20
|
* `text`. GW resolves an omitted `dateTo` to its current time, applies OR
|
|
@@ -37,8 +37,9 @@ export class DigitalTwinSdk {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Searches the public `ResearchSubject/_search` aggregate with FHIR
|
|
40
|
-
* Parameters.
|
|
41
|
-
*
|
|
40
|
+
* Parameters. The high-level match normalizes either mixed claims-first
|
|
41
|
+
* `meta.claims` or a versioned FHIR `contained[]` Composition. Callers never
|
|
42
|
+
* need to navigate either transport representation.
|
|
42
43
|
*
|
|
43
44
|
* MVP basic search supplies `sections`, `dateFrom`, optional `dateTo`, and
|
|
44
45
|
* `text`. GW resolves an omitted `dateTo` to its current time, applies OR
|
|
@@ -80,6 +80,12 @@ export declare class IndividualControllerSdk {
|
|
|
80
80
|
revokeProfessionalAccess(ctx: RouteContext, input: RevokeProfessionalAccessInput): Promise<RevokeProfessionalAccessResult>;
|
|
81
81
|
/**
|
|
82
82
|
* Imports a FHIR/IPS payload and waits until it is indexed.
|
|
83
|
+
*
|
|
84
|
+
* The source `Composition.author` is provenance, not delegated authority.
|
|
85
|
+
* A controller that imports an IPS authored by an external URN does not gain
|
|
86
|
+
* permission to rewrite or delete it. A correction requires independently
|
|
87
|
+
* verified source provenance; merely resubmitting the same URN is
|
|
88
|
+
* insufficient and unsigned/demo imports remain locally immutable.
|
|
83
89
|
*/
|
|
84
90
|
importIpsOrFhirAndUpdateIndex(ctx: RouteContext, input: IpsOrFhirImportInput): Promise<SubmitAndPollResult>;
|
|
85
91
|
/**
|
|
@@ -119,6 +119,12 @@ export class IndividualControllerSdk {
|
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
121
|
* Imports a FHIR/IPS payload and waits until it is indexed.
|
|
122
|
+
*
|
|
123
|
+
* The source `Composition.author` is provenance, not delegated authority.
|
|
124
|
+
* A controller that imports an IPS authored by an external URN does not gain
|
|
125
|
+
* permission to rewrite or delete it. A correction requires independently
|
|
126
|
+
* verified source provenance; merely resubmitting the same URN is
|
|
127
|
+
* insufficient and unsigned/demo imports remain locally immutable.
|
|
122
128
|
*/
|
|
123
129
|
importIpsOrFhirAndUpdateIndex(ctx, input) {
|
|
124
130
|
assertFacadeCapability(this.capabilities, ActorCapabilities.IndividualImportIps, ActorKinds.IndividualController, 'importIpsOrFhirAndUpdateIndex');
|
|
@@ -72,7 +72,11 @@ export type EmployeeActivationGrantInput = Readonly<{
|
|
|
72
72
|
export declare function createEmployeeActivationGrant(input: EmployeeActivationGrantInput): EmployeeActivationGrant;
|
|
73
73
|
/** Verifies that a stored routing grant belongs to the authenticated email. */
|
|
74
74
|
export declare function employeeActivationGrantMatchesEmail(grant: EmployeeActivationGrant, email: string): boolean;
|
|
75
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Stable profile id derived from account, employee, provider and portal
|
|
77
|
+
* installation identities. The portal installation id only separates local
|
|
78
|
+
* profiles; it is not a cryptographic DCR key identifier.
|
|
79
|
+
*/
|
|
76
80
|
export declare function buildOrganizationEmployeeProfileId(input: Readonly<{
|
|
77
81
|
ownerId: string;
|
|
78
82
|
employeeDid: string;
|
|
@@ -187,7 +187,11 @@ export function createEmployeeActivationGrant(input) {
|
|
|
187
187
|
export function employeeActivationGrantMatchesEmail(grant, email) {
|
|
188
188
|
return grant.employeeActorIdentifier === buildStableActorIdentifier({ contactKind: 'email', contact: email });
|
|
189
189
|
}
|
|
190
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* Stable profile id derived from account, employee, provider and portal
|
|
192
|
+
* installation identities. The portal installation id only separates local
|
|
193
|
+
* profiles; it is not a cryptographic DCR key identifier.
|
|
194
|
+
*/
|
|
191
195
|
export function buildOrganizationEmployeeProfileId(input) {
|
|
192
196
|
const digest = createHash('sha256')
|
|
193
197
|
.update([input.ownerId, input.employeeDid, input.providerDid, input.clientInstanceId].join('\u0000'))
|
|
@@ -215,7 +219,6 @@ export async function enrollInvitedOrganizationEmployeeWithDeps(input, deps) {
|
|
|
215
219
|
pin: input.pin,
|
|
216
220
|
idToken: input.idToken,
|
|
217
221
|
activationCode: input.activationCode,
|
|
218
|
-
clientInstanceId: input.clientInstanceId,
|
|
219
222
|
dcrRedirectUris: input.dcrRedirectUris,
|
|
220
223
|
dcrClientName: input.dcrClientName,
|
|
221
224
|
// The grant contains the server-verified stable actor alias and role. The
|
|
@@ -208,6 +208,14 @@ export type IndividualMemberLifecycleInput = {
|
|
|
208
208
|
dataType?: string;
|
|
209
209
|
};
|
|
210
210
|
export type IpsOrFhirImportInput = {
|
|
211
|
+
/**
|
|
212
|
+
* Server-built IPS/FHIR payload whose original Composition author is
|
|
213
|
+
* preserved as provenance. Importing an external `urn:*` author never makes
|
|
214
|
+
* the authenticated controller that author and does not grant local update
|
|
215
|
+
* or delete authority. Repeating the same author URN is not proof that a
|
|
216
|
+
* correction came from the same source; unsigned/demo imports therefore
|
|
217
|
+
* remain locally immutable under the strict audit contract.
|
|
218
|
+
*/
|
|
211
219
|
compositionPayload: {
|
|
212
220
|
thid?: string;
|
|
213
221
|
} & Record<string, unknown>;
|
|
@@ -298,6 +306,8 @@ type ClinicalUpdateRuntimeOptions = Readonly<{
|
|
|
298
306
|
* `ifMatch` for optimistic concurrency. GW authorizes it against the creator
|
|
299
307
|
* DID plus the caller's linked verified login identity; contact identifiers
|
|
300
308
|
* are never written into the clinical resource.
|
|
309
|
+
* An externally authored `urn:*` may be preserved on first import, but a local
|
|
310
|
+
* controller cannot subsequently update or delete that source-authored fact.
|
|
301
311
|
*/
|
|
302
312
|
export type ClinicalSectionUpdateInput = ClinicalSectionUpdateCommunicationInput & ClinicalUpdateRuntimeOptions;
|
|
303
313
|
/** Updates one complete multi-section clinical summary document. */
|
|
@@ -548,7 +548,11 @@ export class ServerProfileSessionManager {
|
|
|
548
548
|
});
|
|
549
549
|
// SMART/OpenID uses its own JSON/form protocol and must not be wrapped in
|
|
550
550
|
// the encrypted resource transport selected for later business actions.
|
|
551
|
-
|
|
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.
|
|
554
|
+
const sdk = new ProfessionalSdk(operationalClient);
|
|
555
|
+
const smartSdk = new ProfessionalSdk(this.createClient(profile.routeContext, idToken));
|
|
552
556
|
const digitalTwin = new DigitalTwinSdk(operationalClient, profile.actorDid);
|
|
553
557
|
let digitalTwinAccessToken;
|
|
554
558
|
const request = async (smart) => {
|
|
@@ -567,7 +571,7 @@ export class ServerProfileSessionManager {
|
|
|
567
571
|
...input.professionalProof,
|
|
568
572
|
role,
|
|
569
573
|
});
|
|
570
|
-
return
|
|
574
|
+
return smartSdk.requestSmartToken({
|
|
571
575
|
...profile.routeContext,
|
|
572
576
|
actorDid: profile.actorDid,
|
|
573
577
|
subjectDid: String(smart.subjectDid || '').trim() || undefined,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdc-sdk-node-ts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
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.
|
|
42
|
-
"gdc-sdk-core-ts": "2.4.
|
|
41
|
+
"gdc-common-utils-ts": "2.7.0",
|
|
42
|
+
"gdc-sdk-core-ts": "2.4.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^20.14.10",
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { VerifiableCredentialV2 } from 'gdc-common-utils-ts/models/verifiable-credential';
|
|
2
|
-
import type { IWallet, WalletExecutionContext, WalletKeySelection } from 'gdc-sdk-core-ts';
|
|
3
|
-
/** Input required to add one human-authorizer proof to the out-of-band VC. */
|
|
4
|
-
export type SignOrganizationRegistrationAuthorizationInput = Readonly<{
|
|
5
|
-
credential: VerifiableCredentialV2;
|
|
6
|
-
wallet: IWallet;
|
|
7
|
-
context: WalletExecutionContext;
|
|
8
|
-
key: WalletKeySelection;
|
|
9
|
-
verificationMethod: string;
|
|
10
|
-
createdAt?: string;
|
|
11
|
-
}>;
|
|
12
|
-
/**
|
|
13
|
-
* Adds one detached JWS proof made by the already-unlocked professional
|
|
14
|
-
* profile. The browser never receives the private key or clear wallet seed.
|
|
15
|
-
*/
|
|
16
|
-
export declare function signOrganizationRegistrationAuthorizationCredential(input: SignOrganizationRegistrationAuthorizationInput): Promise<VerifiableCredentialV2>;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { canonicalizeOrganizationRegistrationAuthorizationCredential, } from 'gdc-common-utils-ts/utils/organization-registration-authorization';
|
|
2
|
-
/**
|
|
3
|
-
* Adds one detached JWS proof made by the already-unlocked professional
|
|
4
|
-
* profile. The browser never receives the private key or clear wallet seed.
|
|
5
|
-
*/
|
|
6
|
-
export async function signOrganizationRegistrationAuthorizationCredential(input) {
|
|
7
|
-
if (!input.wallet.signDetachedJws) {
|
|
8
|
-
throw new Error('Wallet does not support detached organization authorization proofs.');
|
|
9
|
-
}
|
|
10
|
-
const verificationMethod = String(input.verificationMethod || '').trim();
|
|
11
|
-
if (!verificationMethod)
|
|
12
|
-
throw new Error('Organization authorization proof requires verificationMethod.');
|
|
13
|
-
const payload = canonicalizeOrganizationRegistrationAuthorizationCredential(input.credential);
|
|
14
|
-
const jws = await input.wallet.signDetachedJws(input.context, {
|
|
15
|
-
payload,
|
|
16
|
-
header: { typ: 'application/vc+ld+json' },
|
|
17
|
-
key: input.key,
|
|
18
|
-
});
|
|
19
|
-
const existingProofs = Array.isArray(input.credential.proof)
|
|
20
|
-
? input.credential.proof
|
|
21
|
-
: input.credential.proof
|
|
22
|
-
? [input.credential.proof]
|
|
23
|
-
: [];
|
|
24
|
-
return {
|
|
25
|
-
...input.credential,
|
|
26
|
-
proof: [...existingProofs, {
|
|
27
|
-
type: 'JsonWebSignature2020',
|
|
28
|
-
created: input.createdAt || new Date().toISOString(),
|
|
29
|
-
proofPurpose: 'contractAgreement',
|
|
30
|
-
verificationMethod,
|
|
31
|
-
jws,
|
|
32
|
-
}],
|
|
33
|
-
};
|
|
34
|
-
}
|