gdc-common-utils-ts 2.0.2 → 2.0.5
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 +45 -0
- package/dist/constants/verifiable-credentials.d.ts +6 -0
- package/dist/constants/verifiable-credentials.js +6 -0
- package/dist/examples/employee.d.ts +15 -0
- package/dist/examples/employee.js +15 -0
- package/dist/examples/ica-verify-response.d.ts +5 -0
- package/dist/examples/ica-verify-response.js +6 -0
- package/dist/examples/index.d.ts +2 -0
- package/dist/examples/index.js +2 -0
- package/dist/examples/individual-controller.d.ts +25 -0
- package/dist/examples/individual-controller.js +23 -0
- package/dist/examples/legal-organization-verification-transaction.d.ts +1 -0
- package/dist/examples/legal-organization-verification-transaction.js +76 -0
- package/dist/examples/organization-did-binding.d.ts +1 -0
- package/dist/examples/organization-did-binding.js +14 -0
- package/dist/examples/shared.d.ts +10 -0
- package/dist/examples/shared.js +11 -1
- package/dist/utils/bundle-reader.d.ts +2 -0
- package/dist/utils/bundle-reader.js +14 -0
- package/dist/utils/clinical-bundle-summary.d.ts +20 -0
- package/dist/utils/clinical-bundle-summary.js +34 -0
- package/dist/utils/didcomm-submit-policy.d.ts +20 -3
- package/dist/utils/didcomm-submit-policy.js +37 -6
- package/dist/utils/didcomm-submit.d.ts +10 -3
- package/dist/utils/didcomm-submit.js +12 -5
- package/dist/utils/family-organization-summary.d.ts +24 -0
- package/dist/utils/family-organization-summary.js +59 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/legal-organization-onboarding-editor.d.ts +156 -0
- package/dist/utils/legal-organization-onboarding-editor.js +350 -0
- package/dist/utils/legal-organization-verification-transaction.d.ts +130 -0
- package/dist/utils/legal-organization-verification-transaction.js +118 -0
- package/dist/utils/organization-did-binding.d.ts +60 -0
- package/dist/utils/organization-did-binding.js +103 -0
- package/dist/utils/professional-smart.d.ts +21 -0
- package/dist/utils/professional-smart.js +37 -0
- package/dist/utils/related-person-list.d.ts +14 -0
- package/dist/utils/related-person-list.js +31 -0
- package/package.json +1 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { BundleJsonApi } from '../models/bundle';
|
|
2
|
+
import type { ClaimsRecord } from '../models/resource-document';
|
|
3
|
+
/**
|
|
4
|
+
* Canonical business entry type for the first host-side onboarding step that
|
|
5
|
+
* asks GW CORE to forward a legal-organization verification request to ICA.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities of this transaction:
|
|
8
|
+
* - carry the signed PDF evidence or PDF URL attachment
|
|
9
|
+
* - carry the controller business binding key
|
|
10
|
+
* - optionally carry the organization VC-signing public key chosen by the host
|
|
11
|
+
* - carry the legal organization claims that GW CORE should keep through the
|
|
12
|
+
* verification/onboarding pipeline
|
|
13
|
+
*
|
|
14
|
+
* Non-responsibilities:
|
|
15
|
+
* - it is not the same thing as host `_activate`
|
|
16
|
+
* - it does not model Fabric/CSR enrollment
|
|
17
|
+
*/
|
|
18
|
+
export declare const LegalOrganizationVerificationTransactionEntryTypes: Readonly<{
|
|
19
|
+
readonly Request: "Organization-verification-transaction-request-v1.0";
|
|
20
|
+
readonly Response: "Organization-verification-transaction-response-v1.0";
|
|
21
|
+
}>;
|
|
22
|
+
export type LegalOrganizationVerificationTransactionEntryType = typeof LegalOrganizationVerificationTransactionEntryTypes[keyof typeof LegalOrganizationVerificationTransactionEntryTypes];
|
|
23
|
+
/**
|
|
24
|
+
* Explicit controller binding material that ICA should project into the legal
|
|
25
|
+
* representative VC.
|
|
26
|
+
*/
|
|
27
|
+
export type LegalOrganizationVerificationTransactionController = Readonly<{
|
|
28
|
+
did?: string;
|
|
29
|
+
sameAs?: string;
|
|
30
|
+
publicKeyJwk?: Record<string, unknown>;
|
|
31
|
+
jwks?: {
|
|
32
|
+
keys: Array<Record<string, unknown>>;
|
|
33
|
+
};
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Optional organization-side public key material that the hosting operator may
|
|
37
|
+
* already know before the final activation/publication step.
|
|
38
|
+
*/
|
|
39
|
+
export type LegalOrganizationVerificationTransactionOrganization = Readonly<{
|
|
40
|
+
did?: string;
|
|
41
|
+
url?: string;
|
|
42
|
+
publicKeyJwk?: Record<string, unknown>;
|
|
43
|
+
jwks?: {
|
|
44
|
+
keys: Array<Record<string, unknown>>;
|
|
45
|
+
};
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Additional legal-representative payload fields forwarded to ICA `_verify`.
|
|
49
|
+
*
|
|
50
|
+
* These values help ICA derive `sameAs` when the signed document itself does
|
|
51
|
+
* not expose that contact value in a directly reusable way.
|
|
52
|
+
*/
|
|
53
|
+
export type LegalOrganizationVerificationRepresentativePayload = Readonly<{
|
|
54
|
+
email?: string;
|
|
55
|
+
sameAs?: string;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional verification routing hints for ICA.
|
|
59
|
+
*
|
|
60
|
+
* `resourceType` defaults to `contract`, which matches the current
|
|
61
|
+
* legal-organization terms flow in ICA.
|
|
62
|
+
*/
|
|
63
|
+
export type LegalOrganizationVerificationRouting = Readonly<{
|
|
64
|
+
resourceType?: string;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Canonical input accepted by shared SDK/GW helpers when building the first
|
|
68
|
+
* host onboarding transaction that wraps an ICA `_verify` request.
|
|
69
|
+
*/
|
|
70
|
+
export type LegalOrganizationVerificationTransactionInput = Readonly<{
|
|
71
|
+
claims: ClaimsRecord;
|
|
72
|
+
controller: LegalOrganizationVerificationTransactionController;
|
|
73
|
+
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
74
|
+
legalRepresentativePayload?: LegalOrganizationVerificationRepresentativePayload;
|
|
75
|
+
verification?: LegalOrganizationVerificationRouting;
|
|
76
|
+
attachments?: unknown[];
|
|
77
|
+
}>;
|
|
78
|
+
export type LegalOrganizationVerificationTransactionEntry = Readonly<{
|
|
79
|
+
type?: string;
|
|
80
|
+
meta?: {
|
|
81
|
+
claims?: ClaimsRecord;
|
|
82
|
+
[key: string]: unknown;
|
|
83
|
+
};
|
|
84
|
+
resource?: {
|
|
85
|
+
controller?: LegalOrganizationVerificationTransactionController;
|
|
86
|
+
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
87
|
+
legalRepresentativePayload?: LegalOrganizationVerificationRepresentativePayload;
|
|
88
|
+
legalRepresentative?: LegalOrganizationVerificationRepresentativePayload;
|
|
89
|
+
verification?: LegalOrganizationVerificationRouting;
|
|
90
|
+
[key: string]: unknown;
|
|
91
|
+
};
|
|
92
|
+
[key: string]: unknown;
|
|
93
|
+
}>;
|
|
94
|
+
/**
|
|
95
|
+
* Builds the canonical Bundle payload for host-side legal organization
|
|
96
|
+
* verification transactions.
|
|
97
|
+
*
|
|
98
|
+
* Contract notes:
|
|
99
|
+
* - business claims remain in `meta.claims`
|
|
100
|
+
* - controller binding material remains in `resource.controller.*`
|
|
101
|
+
* - organization signing material remains in `resource.organization.*`
|
|
102
|
+
* - PDF evidence or URL attachments stay at the DIDComm-message level
|
|
103
|
+
* - `Service.category` is the canonical business-sector input later used by GW
|
|
104
|
+
* to target the appropriate ICA verification route
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildLegalOrganizationVerificationTransactionBundle(input: LegalOrganizationVerificationTransactionInput): BundleJsonApi;
|
|
107
|
+
/**
|
|
108
|
+
* Returns the first bundle entry when the payload matches the canonical
|
|
109
|
+
* legal-organization verification transaction shape.
|
|
110
|
+
*
|
|
111
|
+
* This helper accepts either:
|
|
112
|
+
* - the raw bundle itself
|
|
113
|
+
* - or a DIDComm/API wrapper object whose `body` contains that bundle
|
|
114
|
+
*/
|
|
115
|
+
export declare function getFirstLegalOrganizationVerificationTransactionEntry(value: unknown): LegalOrganizationVerificationTransactionEntry | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Returns the normalized controller binding payload from the first legal
|
|
118
|
+
* organization verification transaction entry when present.
|
|
119
|
+
*/
|
|
120
|
+
export declare function getLegalOrganizationVerificationController(value: unknown): LegalOrganizationVerificationTransactionController | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Returns the normalized legal representative contact payload from the first
|
|
123
|
+
* legal-organization verification transaction entry when present.
|
|
124
|
+
*
|
|
125
|
+
* Compatibility note:
|
|
126
|
+
* - GW/SDK request builders use `resource.legalRepresentativePayload`
|
|
127
|
+
* - the ICA forwarding payload currently uses `resource.legalRepresentative`
|
|
128
|
+
* - this helper intentionally accepts both shapes
|
|
129
|
+
*/
|
|
130
|
+
export declare function getLegalOrganizationVerificationRepresentativePayload(value: unknown): LegalOrganizationVerificationRepresentativePayload | undefined;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { ClaimsServiceSchemaorg } from '../constants/schemaorg.js';
|
|
2
|
+
/**
|
|
3
|
+
* Canonical business entry type for the first host-side onboarding step that
|
|
4
|
+
* asks GW CORE to forward a legal-organization verification request to ICA.
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities of this transaction:
|
|
7
|
+
* - carry the signed PDF evidence or PDF URL attachment
|
|
8
|
+
* - carry the controller business binding key
|
|
9
|
+
* - optionally carry the organization VC-signing public key chosen by the host
|
|
10
|
+
* - carry the legal organization claims that GW CORE should keep through the
|
|
11
|
+
* verification/onboarding pipeline
|
|
12
|
+
*
|
|
13
|
+
* Non-responsibilities:
|
|
14
|
+
* - it is not the same thing as host `_activate`
|
|
15
|
+
* - it does not model Fabric/CSR enrollment
|
|
16
|
+
*/
|
|
17
|
+
export const LegalOrganizationVerificationTransactionEntryTypes = Object.freeze({
|
|
18
|
+
Request: 'Organization-verification-transaction-request-v1.0',
|
|
19
|
+
Response: 'Organization-verification-transaction-response-v1.0',
|
|
20
|
+
});
|
|
21
|
+
function normalizeText(value) {
|
|
22
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
23
|
+
}
|
|
24
|
+
function asRecord(value) {
|
|
25
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
26
|
+
? value
|
|
27
|
+
: undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds the canonical Bundle payload for host-side legal organization
|
|
31
|
+
* verification transactions.
|
|
32
|
+
*
|
|
33
|
+
* Contract notes:
|
|
34
|
+
* - business claims remain in `meta.claims`
|
|
35
|
+
* - controller binding material remains in `resource.controller.*`
|
|
36
|
+
* - organization signing material remains in `resource.organization.*`
|
|
37
|
+
* - PDF evidence or URL attachments stay at the DIDComm-message level
|
|
38
|
+
* - `Service.category` is the canonical business-sector input later used by GW
|
|
39
|
+
* to target the appropriate ICA verification route
|
|
40
|
+
*/
|
|
41
|
+
export function buildLegalOrganizationVerificationTransactionBundle(input) {
|
|
42
|
+
const businessSector = normalizeText(input.claims?.[ClaimsServiceSchemaorg.category]);
|
|
43
|
+
if (!businessSector) {
|
|
44
|
+
throw new Error(`buildLegalOrganizationVerificationTransactionBundle requires ${ClaimsServiceSchemaorg.category}.`);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
resourceType: 'Bundle',
|
|
48
|
+
type: 'collection',
|
|
49
|
+
total: 1,
|
|
50
|
+
data: [{
|
|
51
|
+
type: LegalOrganizationVerificationTransactionEntryTypes.Request,
|
|
52
|
+
meta: {
|
|
53
|
+
claims: input.claims,
|
|
54
|
+
},
|
|
55
|
+
resource: {
|
|
56
|
+
controller: input.controller,
|
|
57
|
+
...(input.organization ? { organization: input.organization } : {}),
|
|
58
|
+
...(input.legalRepresentativePayload
|
|
59
|
+
? { legalRepresentativePayload: input.legalRepresentativePayload }
|
|
60
|
+
: {}),
|
|
61
|
+
verification: {
|
|
62
|
+
resourceType: normalizeText(input.verification?.resourceType) || 'contract',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
}],
|
|
66
|
+
...(Array.isArray(input.attachments) && input.attachments.length > 0
|
|
67
|
+
? { attachments: input.attachments }
|
|
68
|
+
: {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the first bundle entry when the payload matches the canonical
|
|
73
|
+
* legal-organization verification transaction shape.
|
|
74
|
+
*
|
|
75
|
+
* This helper accepts either:
|
|
76
|
+
* - the raw bundle itself
|
|
77
|
+
* - or a DIDComm/API wrapper object whose `body` contains that bundle
|
|
78
|
+
*/
|
|
79
|
+
export function getFirstLegalOrganizationVerificationTransactionEntry(value) {
|
|
80
|
+
const root = asRecord(value);
|
|
81
|
+
const bundle = asRecord(root?.body) || root;
|
|
82
|
+
const data = Array.isArray(bundle?.data) ? bundle.data : [];
|
|
83
|
+
const first = data[0];
|
|
84
|
+
return asRecord(first);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Returns the normalized controller binding payload from the first legal
|
|
88
|
+
* organization verification transaction entry when present.
|
|
89
|
+
*/
|
|
90
|
+
export function getLegalOrganizationVerificationController(value) {
|
|
91
|
+
const entry = getFirstLegalOrganizationVerificationTransactionEntry(value);
|
|
92
|
+
const controller = asRecord(entry?.resource?.controller);
|
|
93
|
+
return controller
|
|
94
|
+
? controller
|
|
95
|
+
: undefined;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns the normalized legal representative contact payload from the first
|
|
99
|
+
* legal-organization verification transaction entry when present.
|
|
100
|
+
*
|
|
101
|
+
* Compatibility note:
|
|
102
|
+
* - GW/SDK request builders use `resource.legalRepresentativePayload`
|
|
103
|
+
* - the ICA forwarding payload currently uses `resource.legalRepresentative`
|
|
104
|
+
* - this helper intentionally accepts both shapes
|
|
105
|
+
*/
|
|
106
|
+
export function getLegalOrganizationVerificationRepresentativePayload(value) {
|
|
107
|
+
const entry = getFirstLegalOrganizationVerificationTransactionEntry(value);
|
|
108
|
+
const candidate = asRecord(entry?.resource?.legalRepresentativePayload)
|
|
109
|
+
|| asRecord(entry?.resource?.legalRepresentative);
|
|
110
|
+
if (!candidate)
|
|
111
|
+
return undefined;
|
|
112
|
+
const email = normalizeText(candidate.email);
|
|
113
|
+
const sameAs = normalizeText(candidate.sameAs);
|
|
114
|
+
return {
|
|
115
|
+
...(email ? { email } : {}),
|
|
116
|
+
...(sameAs ? { sameAs } : {}),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { BundleJsonApi } from '../models/bundle';
|
|
2
|
+
export declare const OrganizationDidBindingEntryTypes: Readonly<{
|
|
3
|
+
readonly Request: "Organization-did-binding-request-v1.0";
|
|
4
|
+
readonly Response: "Organization-did-binding-response-v1.0";
|
|
5
|
+
}>;
|
|
6
|
+
export type OrganizationDidBindingErrorCode = 'MISSING_ORGANIZATION_URL' | 'UNSUPPORTED_ORGANIZATION_LOCATOR';
|
|
7
|
+
export type OrganizationDidBindingValidationError = Readonly<{
|
|
8
|
+
code: OrganizationDidBindingErrorCode;
|
|
9
|
+
message: string;
|
|
10
|
+
claimPaths: string[];
|
|
11
|
+
}>;
|
|
12
|
+
export type OrganizationDidBindingControllerInput = Readonly<{
|
|
13
|
+
sameAs?: string;
|
|
14
|
+
}>;
|
|
15
|
+
export type OrganizationDidBindingOrganizationInput = Readonly<{
|
|
16
|
+
url: string | string[];
|
|
17
|
+
taxID?: string;
|
|
18
|
+
taxId?: string;
|
|
19
|
+
identifier?: string;
|
|
20
|
+
}>;
|
|
21
|
+
export type OrganizationDidBindingInput = Readonly<{
|
|
22
|
+
organization: OrganizationDidBindingOrganizationInput;
|
|
23
|
+
controller?: OrganizationDidBindingControllerInput;
|
|
24
|
+
}>;
|
|
25
|
+
export type ValidateOrganizationDidBindingInputResult = Readonly<{
|
|
26
|
+
ok: boolean;
|
|
27
|
+
errors: OrganizationDidBindingValidationError[];
|
|
28
|
+
normalizedInput: Readonly<{
|
|
29
|
+
organization: {
|
|
30
|
+
url: string[];
|
|
31
|
+
};
|
|
32
|
+
controller?: OrganizationDidBindingControllerInput;
|
|
33
|
+
}>;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Validates the tenant-scoped organization DID binding request.
|
|
37
|
+
*
|
|
38
|
+
* Canonical contract:
|
|
39
|
+
* - the organization is already identified by the tenant path in GW CORE
|
|
40
|
+
* - callers send one or more public aliases in `organization.url`
|
|
41
|
+
* - `controller.sameAs` is optional additional evidence, not a new key-binding
|
|
42
|
+
* bootstrap step
|
|
43
|
+
*
|
|
44
|
+
* Current version limits:
|
|
45
|
+
* - no `taxID` / `identifier` locator is required
|
|
46
|
+
* - sending those legacy locator fields is rejected so callers do not mix path
|
|
47
|
+
* identity with payload identity
|
|
48
|
+
*/
|
|
49
|
+
export declare function validateOrganizationDidBindingInput(input: OrganizationDidBindingInput): ValidateOrganizationDidBindingInputResult;
|
|
50
|
+
/**
|
|
51
|
+
* Builds the canonical bundle payload for one tenant-scoped DID binding
|
|
52
|
+
* request.
|
|
53
|
+
*
|
|
54
|
+
* Result contract:
|
|
55
|
+
* - `resource.organization.url` carries the public alias replacement list
|
|
56
|
+
* - `resource.controller.sameAs` is optional corroborating identity material
|
|
57
|
+
* - organization identity is resolved from the tenant path, not from payload
|
|
58
|
+
* locators
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildOrganizationDidBindingBundle(input: OrganizationDidBindingInput): BundleJsonApi;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export const OrganizationDidBindingEntryTypes = Object.freeze({
|
|
2
|
+
Request: 'Organization-did-binding-request-v1.0',
|
|
3
|
+
Response: 'Organization-did-binding-response-v1.0',
|
|
4
|
+
});
|
|
5
|
+
function normalizeOptionalText(value) {
|
|
6
|
+
if (typeof value !== 'string')
|
|
7
|
+
return undefined;
|
|
8
|
+
const trimmed = value.trim();
|
|
9
|
+
return trimmed.length ? trimmed : undefined;
|
|
10
|
+
}
|
|
11
|
+
function normalizeOrganizationUrls(value) {
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
const urls = value
|
|
14
|
+
.map((item) => normalizeOptionalText(item))
|
|
15
|
+
.filter((item) => Boolean(item));
|
|
16
|
+
return urls.length ? urls : undefined;
|
|
17
|
+
}
|
|
18
|
+
const raw = normalizeOptionalText(value);
|
|
19
|
+
if (!raw)
|
|
20
|
+
return undefined;
|
|
21
|
+
const urls = raw
|
|
22
|
+
.split(',')
|
|
23
|
+
.map((item) => item.trim())
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
return urls.length ? urls : undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validates the tenant-scoped organization DID binding request.
|
|
29
|
+
*
|
|
30
|
+
* Canonical contract:
|
|
31
|
+
* - the organization is already identified by the tenant path in GW CORE
|
|
32
|
+
* - callers send one or more public aliases in `organization.url`
|
|
33
|
+
* - `controller.sameAs` is optional additional evidence, not a new key-binding
|
|
34
|
+
* bootstrap step
|
|
35
|
+
*
|
|
36
|
+
* Current version limits:
|
|
37
|
+
* - no `taxID` / `identifier` locator is required
|
|
38
|
+
* - sending those legacy locator fields is rejected so callers do not mix path
|
|
39
|
+
* identity with payload identity
|
|
40
|
+
*/
|
|
41
|
+
export function validateOrganizationDidBindingInput(input) {
|
|
42
|
+
const errors = [];
|
|
43
|
+
const normalizedUrls = normalizeOrganizationUrls(input?.organization?.url);
|
|
44
|
+
const taxID = normalizeOptionalText(input?.organization?.taxID || input?.organization?.taxId);
|
|
45
|
+
const identifier = normalizeOptionalText(input?.organization?.identifier);
|
|
46
|
+
const controllerSameAs = normalizeOptionalText(input?.controller?.sameAs);
|
|
47
|
+
if (!normalizedUrls?.length) {
|
|
48
|
+
errors.push({
|
|
49
|
+
code: 'MISSING_ORGANIZATION_URL',
|
|
50
|
+
message: 'Organization DID binding requires at least one organization.url value.',
|
|
51
|
+
claimPaths: ['organization.url'],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (taxID || identifier) {
|
|
55
|
+
errors.push({
|
|
56
|
+
code: 'UNSUPPORTED_ORGANIZATION_LOCATOR',
|
|
57
|
+
message: 'Organization DID binding in GW CORE uses the tenant path as locator and does not accept organization.taxID or organization.identifier in this version.',
|
|
58
|
+
claimPaths: ['organization.taxID', 'organization.identifier'],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
ok: errors.length === 0,
|
|
63
|
+
errors,
|
|
64
|
+
normalizedInput: {
|
|
65
|
+
organization: {
|
|
66
|
+
url: normalizedUrls || [],
|
|
67
|
+
},
|
|
68
|
+
...(controllerSameAs ? { controller: { sameAs: controllerSameAs } } : {}),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Builds the canonical bundle payload for one tenant-scoped DID binding
|
|
74
|
+
* request.
|
|
75
|
+
*
|
|
76
|
+
* Result contract:
|
|
77
|
+
* - `resource.organization.url` carries the public alias replacement list
|
|
78
|
+
* - `resource.controller.sameAs` is optional corroborating identity material
|
|
79
|
+
* - organization identity is resolved from the tenant path, not from payload
|
|
80
|
+
* locators
|
|
81
|
+
*/
|
|
82
|
+
export function buildOrganizationDidBindingBundle(input) {
|
|
83
|
+
const validation = validateOrganizationDidBindingInput(input);
|
|
84
|
+
if (!validation.ok) {
|
|
85
|
+
throw new Error(validation.errors.map((item) => item.message).join(' '));
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
resourceType: 'Bundle',
|
|
89
|
+
type: 'collection',
|
|
90
|
+
total: 1,
|
|
91
|
+
data: [{
|
|
92
|
+
type: OrganizationDidBindingEntryTypes.Request,
|
|
93
|
+
resource: {
|
|
94
|
+
organization: {
|
|
95
|
+
url: validation.normalizedInput.organization.url,
|
|
96
|
+
},
|
|
97
|
+
...(validation.normalizedInput.controller
|
|
98
|
+
? { controller: validation.normalizedInput.controller }
|
|
99
|
+
: {}),
|
|
100
|
+
},
|
|
101
|
+
}],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ProfessionalEmployeeCredentialInput = Readonly<{
|
|
2
|
+
actorDid: string;
|
|
3
|
+
role: string;
|
|
4
|
+
additionalCredentialSubject?: Record<string, unknown>;
|
|
5
|
+
additionalCredential?: Record<string, unknown>;
|
|
6
|
+
}>;
|
|
7
|
+
export type ProfessionalSmartVpPayloadInput = Readonly<{
|
|
8
|
+
clientId: string;
|
|
9
|
+
actorDid: string;
|
|
10
|
+
role: string;
|
|
11
|
+
verifiableCredential?: string | Record<string, unknown> | ReadonlyArray<string | Record<string, unknown>>;
|
|
12
|
+
additionalVp?: Record<string, unknown>;
|
|
13
|
+
additionalPayload?: Record<string, unknown>;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function buildProfessionalEmployeeCredential(input: ProfessionalEmployeeCredentialInput): Record<string, unknown>;
|
|
16
|
+
export declare function buildProfessionalSmartVpPayload(input: ProfessionalSmartVpPayloadInput): Record<string, unknown>;
|
|
17
|
+
export declare function buildUnsignedProfessionalSmartVpJwt(input: ProfessionalSmartVpPayloadInput, options?: Readonly<{
|
|
18
|
+
nowSeconds?: number;
|
|
19
|
+
ttlSeconds?: number;
|
|
20
|
+
nonce?: string;
|
|
21
|
+
}>): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ProfessionalCredentialTypes, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
|
|
2
|
+
import { buildUnsignedVpJwt } from './jwt.js';
|
|
3
|
+
export function buildProfessionalEmployeeCredential(input) {
|
|
4
|
+
return {
|
|
5
|
+
type: [
|
|
6
|
+
W3cCredentialTypes.VerifiableCredential,
|
|
7
|
+
ProfessionalCredentialTypes.EmployeeCredential,
|
|
8
|
+
],
|
|
9
|
+
credentialSubject: {
|
|
10
|
+
id: String(input.actorDid || '').trim(),
|
|
11
|
+
hasOccupation: String(input.role || '').trim(),
|
|
12
|
+
...(input.additionalCredentialSubject || {}),
|
|
13
|
+
},
|
|
14
|
+
...(input.additionalCredential || {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function buildProfessionalSmartVpPayload(input) {
|
|
18
|
+
const credentials = Array.isArray(input.verifiableCredential)
|
|
19
|
+
? [...input.verifiableCredential]
|
|
20
|
+
: input.verifiableCredential
|
|
21
|
+
? [input.verifiableCredential]
|
|
22
|
+
: [buildProfessionalEmployeeCredential({
|
|
23
|
+
actorDid: input.actorDid,
|
|
24
|
+
role: input.role,
|
|
25
|
+
})];
|
|
26
|
+
return {
|
|
27
|
+
...(input.additionalPayload || {}),
|
|
28
|
+
vp: {
|
|
29
|
+
holder: String(input.clientId || '').trim(),
|
|
30
|
+
verifiableCredential: credentials,
|
|
31
|
+
...(input.additionalVp || {}),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function buildUnsignedProfessionalSmartVpJwt(input, options = {}) {
|
|
36
|
+
return buildUnsignedVpJwt(buildProfessionalSmartVpPayload(input), options);
|
|
37
|
+
}
|
|
@@ -9,6 +9,14 @@ export type RelatedPersonListRecord = Readonly<{
|
|
|
9
9
|
resourceId?: string;
|
|
10
10
|
claims: Record<string, unknown>;
|
|
11
11
|
}>;
|
|
12
|
+
export type RelatedPersonListSelection = Readonly<{
|
|
13
|
+
index?: number;
|
|
14
|
+
identifier?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
telecom?: string;
|
|
17
|
+
patient?: string;
|
|
18
|
+
activeOnly?: boolean;
|
|
19
|
+
}>;
|
|
12
20
|
/**
|
|
13
21
|
* Reads subject-side relationship records from one current GW-style result
|
|
14
22
|
* body into one neutral list shape for frontend screens.
|
|
@@ -18,3 +26,9 @@ export declare function readRelatedPersonListRecords(body: unknown): RelatedPers
|
|
|
18
26
|
* Returns one related-person record by canonical business identifier.
|
|
19
27
|
*/
|
|
20
28
|
export declare function findRelatedPersonListRecord(body: unknown, identifier: string): RelatedPersonListRecord | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Selects one related-person record from one neutralized list/body using the
|
|
31
|
+
* same high-level criteria that channel apps usually expose to users:
|
|
32
|
+
* list position, identifier, display name, contact value, or linked patient.
|
|
33
|
+
*/
|
|
34
|
+
export declare function selectRelatedPersonListRecord(body: unknown, selection: RelatedPersonListSelection): RelatedPersonListRecord | undefined;
|
|
@@ -52,3 +52,34 @@ export function findRelatedPersonListRecord(body, identifier) {
|
|
|
52
52
|
return readRelatedPersonListRecords(body)
|
|
53
53
|
.find((record) => record.identifier === normalizedIdentifier);
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Selects one related-person record from one neutralized list/body using the
|
|
57
|
+
* same high-level criteria that channel apps usually expose to users:
|
|
58
|
+
* list position, identifier, display name, contact value, or linked patient.
|
|
59
|
+
*/
|
|
60
|
+
export function selectRelatedPersonListRecord(body, selection) {
|
|
61
|
+
const records = readRelatedPersonListRecords(body);
|
|
62
|
+
const candidates = selection.activeOnly
|
|
63
|
+
? records.filter((record) => record.active === 'true')
|
|
64
|
+
: records;
|
|
65
|
+
if (typeof selection.index === 'number' && Number.isInteger(selection.index)) {
|
|
66
|
+
return candidates[selection.index];
|
|
67
|
+
}
|
|
68
|
+
const identifier = normalizeText(selection.identifier);
|
|
69
|
+
if (identifier) {
|
|
70
|
+
return candidates.find((record) => record.identifier === identifier);
|
|
71
|
+
}
|
|
72
|
+
const name = normalizeText(selection.name)?.toLowerCase();
|
|
73
|
+
if (name) {
|
|
74
|
+
return candidates.find((record) => normalizeText(record.name)?.toLowerCase() === name);
|
|
75
|
+
}
|
|
76
|
+
const telecom = normalizeText(selection.telecom)?.toLowerCase();
|
|
77
|
+
if (telecom) {
|
|
78
|
+
return candidates.find((record) => normalizeText(record.telecom)?.toLowerCase() === telecom);
|
|
79
|
+
}
|
|
80
|
+
const patient = normalizeText(selection.patient);
|
|
81
|
+
if (patient) {
|
|
82
|
+
return candidates.find((record) => record.patient === patient);
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|