gdc-common-utils-ts 2.0.4 → 2.0.6
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/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/individual-controller.d.ts +25 -0
- package/dist/examples/individual-controller.js +23 -0
- package/dist/examples/legal-organization-verification-transaction.js +10 -0
- package/dist/examples/shared.d.ts +7 -0
- package/dist/examples/shared.js +8 -1
- package/dist/utils/activation-request.d.ts +3 -3
- package/dist/utils/activation-request.js +3 -3
- 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 +4 -0
- package/dist/utils/index.js +4 -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 +40 -0
- package/dist/utils/legal-organization-verification-transaction.js +53 -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
|
@@ -30,5 +30,11 @@ export declare const ActivationCredentialTypes: Readonly<{
|
|
|
30
30
|
LegalRepresentativeCredential: "LegalRepresentativeCredential";
|
|
31
31
|
PersonCredential: "PersonCredential";
|
|
32
32
|
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Canonical credential subtype names used by professional/member access flows.
|
|
35
|
+
*/
|
|
36
|
+
export declare const ProfessionalCredentialTypes: Readonly<{
|
|
37
|
+
EmployeeCredential: "EmployeeCredential";
|
|
38
|
+
}>;
|
|
33
39
|
export declare const ORGANIZATION_ACTIVATION_VC_TYPES: readonly ("OrganizationCredential" | "LegalOrganizationCredential")[];
|
|
34
40
|
export declare const REPRESENTATIVE_ACTIVATION_VC_TYPES: readonly ("LegalRepresentativeCredential" | "PersonCredential")[];
|
|
@@ -32,6 +32,12 @@ export const ActivationCredentialTypes = Object.freeze({
|
|
|
32
32
|
LegalRepresentativeCredential: 'LegalRepresentativeCredential',
|
|
33
33
|
PersonCredential: 'PersonCredential',
|
|
34
34
|
});
|
|
35
|
+
/**
|
|
36
|
+
* Canonical credential subtype names used by professional/member access flows.
|
|
37
|
+
*/
|
|
38
|
+
export const ProfessionalCredentialTypes = Object.freeze({
|
|
39
|
+
EmployeeCredential: 'EmployeeCredential',
|
|
40
|
+
});
|
|
35
41
|
export const ORGANIZATION_ACTIVATION_VC_TYPES = Object.freeze([
|
|
36
42
|
ActivationCredentialTypes.OrganizationCredential,
|
|
37
43
|
ActivationCredentialTypes.LegalOrganizationCredential,
|
|
@@ -39,3 +39,18 @@ export declare const EXAMPLE_EMPLOYEE_DIRECTORY_RECORDS: readonly [Readonly<{
|
|
|
39
39
|
status: "active" | "inactive" | "purged";
|
|
40
40
|
}>];
|
|
41
41
|
export declare function buildExampleEmployeeClaims(record: ExampleEmployeeRecord): Readonly<Record<string, string>>;
|
|
42
|
+
/**
|
|
43
|
+
* Canonical employee search/list response body reused by runtime and doc tests.
|
|
44
|
+
*
|
|
45
|
+
* This keeps one stable GW-style envelope for high-level tutorials that want
|
|
46
|
+
* to show employee directory flows without reauthoring `meta.claims` by hand.
|
|
47
|
+
*/
|
|
48
|
+
export declare const EXAMPLE_EMPLOYEE_SEARCH_RESPONSE_BODY: Readonly<{
|
|
49
|
+
readonly data: {
|
|
50
|
+
id: string;
|
|
51
|
+
meta: {
|
|
52
|
+
status: "active" | "inactive" | "purged";
|
|
53
|
+
claims: Readonly<Record<string, string>>;
|
|
54
|
+
};
|
|
55
|
+
}[];
|
|
56
|
+
}>;
|
|
@@ -37,3 +37,18 @@ export function buildExampleEmployeeClaims(record) {
|
|
|
37
37
|
[ClaimsPersonSchemaorg.hasOccupationalRoleValue]: record.role,
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Canonical employee search/list response body reused by runtime and doc tests.
|
|
42
|
+
*
|
|
43
|
+
* This keeps one stable GW-style envelope for high-level tutorials that want
|
|
44
|
+
* to show employee directory flows without reauthoring `meta.claims` by hand.
|
|
45
|
+
*/
|
|
46
|
+
export const EXAMPLE_EMPLOYEE_SEARCH_RESPONSE_BODY = Object.freeze({
|
|
47
|
+
data: EXAMPLE_EMPLOYEE_DIRECTORY_RECORDS.map((record) => ({
|
|
48
|
+
id: record.identifier,
|
|
49
|
+
meta: {
|
|
50
|
+
status: record.status,
|
|
51
|
+
claims: buildExampleEmployeeClaims(record),
|
|
52
|
+
},
|
|
53
|
+
})),
|
|
54
|
+
});
|
|
@@ -98,3 +98,28 @@ export declare const EXAMPLE_DIGITAL_TWIN_COMPOSITION_INPUT: {
|
|
|
98
98
|
};
|
|
99
99
|
export declare const EXAMPLE_CLINICAL_BUNDLE_SEARCH_INPUT: ExampleClinicalBundleSearchInput;
|
|
100
100
|
export declare const EXAMPLE_LATEST_IPS_SEARCH_INPUT: ExampleLatestIpsSearchInput;
|
|
101
|
+
export declare const EXAMPLE_FAMILY_ORGANIZATION_SEARCH_INPUT: {
|
|
102
|
+
readonly controllerPhone: "+34600000001";
|
|
103
|
+
readonly usualname: "Ana";
|
|
104
|
+
readonly birthDate: "2010-05-20";
|
|
105
|
+
};
|
|
106
|
+
export declare const EXAMPLE_FAMILY_ORGANIZATION_SEARCH_RESPONSE_BODY: {
|
|
107
|
+
readonly body: {
|
|
108
|
+
readonly data: readonly [{
|
|
109
|
+
readonly type: "Family-search-result-v1.0";
|
|
110
|
+
readonly meta: {
|
|
111
|
+
readonly claims: {
|
|
112
|
+
readonly 'org.schema.FamilyRegistration.status': "already_exists";
|
|
113
|
+
readonly 'org.schema.Offer.identifier': "offer-uuid-001";
|
|
114
|
+
readonly 'org.schema.Organization.identifier.value': "org-uuid-001";
|
|
115
|
+
readonly 'org.schema.Organization.alternateName': "Ana";
|
|
116
|
+
readonly 'org.schema.Organization.owner.telephone': "+34600000001";
|
|
117
|
+
readonly 'org.schema.Organization.foundingDate': "2010-05-20";
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
readonly resource: {
|
|
121
|
+
readonly id: "org-uuid-001";
|
|
122
|
+
};
|
|
123
|
+
}];
|
|
124
|
+
};
|
|
125
|
+
};
|
|
@@ -69,3 +69,26 @@ export const EXAMPLE_CLINICAL_BUNDLE_SEARCH_INPUT = {
|
|
|
69
69
|
export const EXAMPLE_LATEST_IPS_SEARCH_INPUT = {
|
|
70
70
|
subject: EXAMPLE_SUBJECT_DID,
|
|
71
71
|
};
|
|
72
|
+
export const EXAMPLE_FAMILY_ORGANIZATION_SEARCH_INPUT = {
|
|
73
|
+
controllerPhone: '+34600000001',
|
|
74
|
+
usualname: 'Ana',
|
|
75
|
+
birthDate: '2010-05-20',
|
|
76
|
+
};
|
|
77
|
+
export const EXAMPLE_FAMILY_ORGANIZATION_SEARCH_RESPONSE_BODY = {
|
|
78
|
+
body: {
|
|
79
|
+
data: [{
|
|
80
|
+
type: 'Family-search-result-v1.0',
|
|
81
|
+
meta: {
|
|
82
|
+
claims: {
|
|
83
|
+
'org.schema.FamilyRegistration.status': 'already_exists',
|
|
84
|
+
'org.schema.Offer.identifier': 'offer-uuid-001',
|
|
85
|
+
'org.schema.Organization.identifier.value': 'org-uuid-001',
|
|
86
|
+
'org.schema.Organization.alternateName': EXAMPLE_FAMILY_ORGANIZATION_SEARCH_INPUT.usualname,
|
|
87
|
+
'org.schema.Organization.owner.telephone': EXAMPLE_FAMILY_ORGANIZATION_SEARCH_INPUT.controllerPhone,
|
|
88
|
+
'org.schema.Organization.foundingDate': EXAMPLE_FAMILY_ORGANIZATION_SEARCH_INPUT.birthDate,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
resource: { id: 'org-uuid-001' },
|
|
92
|
+
}],
|
|
93
|
+
},
|
|
94
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { ClaimsOrganizationSchemaorg, ClaimsPersonSchemaorg, ClaimsServiceSchemaorg, } from '../constants/schemaorg.js';
|
|
3
|
+
import { serializeServiceCapabilityTokens, ServiceCapability, } from '../constants/service-capabilities.js';
|
|
3
4
|
import { buildLegalOrganizationVerificationTransactionBundle, } from '../utils/legal-organization-verification-transaction.js';
|
|
4
5
|
import { EXAMPLE_CONTROLLER_BINDING, EXAMPLE_EMAIL_CONTROLLER_ORG, EXAMPLE_JURISDICTION, EXAMPLE_ORGANIZATION_LEGAL_NAME, EXAMPLE_LEGAL_ORGANIZATION_TAX_ID, EXAMPLE_SECTOR, EXAMPLE_SIGNED_TERMS_PDF_URL, EXAMPLE_TENANT_SERVICE_DID, } from './shared.js';
|
|
5
6
|
/**
|
|
@@ -11,6 +12,11 @@ import { EXAMPLE_CONTROLLER_BINDING, EXAMPLE_EMAIL_CONTROLLER_ORG, EXAMPLE_JURIS
|
|
|
11
12
|
* that wraps an ICA `_verify`
|
|
12
13
|
* - the example keeps the controller business binding separate from any
|
|
13
14
|
* technical DIDComm communication key
|
|
15
|
+
*
|
|
16
|
+
* Contract note:
|
|
17
|
+
* - the same request must already declare the requested tenant service
|
|
18
|
+
* capabilities because GW uses them to prepare the pending Offer that the
|
|
19
|
+
* client will later confirm via `Order/_batch`
|
|
14
20
|
*/
|
|
15
21
|
const exampleControllerBinding = {
|
|
16
22
|
did: EXAMPLE_CONTROLLER_BINDING.did,
|
|
@@ -36,6 +42,10 @@ export const EXAMPLE_LEGAL_ORGANIZATION_VERIFICATION_TRANSACTION_BUNDLE = buildL
|
|
|
36
42
|
[ClaimsServiceSchemaorg.category]: EXAMPLE_SECTOR,
|
|
37
43
|
[ClaimsServiceSchemaorg.identifier]: EXAMPLE_TENANT_SERVICE_DID,
|
|
38
44
|
[ClaimsServiceSchemaorg.url]: `https://operator.example.net/acme/cds-${String(EXAMPLE_JURISDICTION).toLowerCase()}/v1/${EXAMPLE_SECTOR}`,
|
|
45
|
+
[ClaimsServiceSchemaorg.serviceType]: serializeServiceCapabilityTokens([
|
|
46
|
+
ServiceCapability.IndexProvider,
|
|
47
|
+
ServiceCapability.DigitalTwinReader,
|
|
48
|
+
]),
|
|
39
49
|
},
|
|
40
50
|
controller: exampleControllerBinding,
|
|
41
51
|
organization: {
|
|
@@ -91,6 +91,13 @@ export declare const EXAMPLE_TENANT_ROUTE_CONTEXT: {
|
|
|
91
91
|
export declare const EXAMPLE_HOST_ROUTE_CONTEXT: {
|
|
92
92
|
readonly hostCoverageScope: "EU";
|
|
93
93
|
readonly jurisdiction: "ES";
|
|
94
|
+
/**
|
|
95
|
+
* Host route segment used in `/host/cds-{hostCoverageScope}/v1/{hostNetwork}/...`.
|
|
96
|
+
*
|
|
97
|
+
* This is intentionally not the tenant business sector.
|
|
98
|
+
*/
|
|
99
|
+
readonly hostNetwork: "test";
|
|
100
|
+
/** @deprecated Use `hostNetwork`. */
|
|
94
101
|
readonly sector: "test";
|
|
95
102
|
};
|
|
96
103
|
export declare const EXAMPLE_CONTROLLER_DID: "did:web:people.acme.org:controllers:primary";
|
package/dist/examples/shared.js
CHANGED
|
@@ -106,7 +106,14 @@ export const EXAMPLE_TENANT_ROUTE_CONTEXT = {
|
|
|
106
106
|
export const EXAMPLE_HOST_ROUTE_CONTEXT = {
|
|
107
107
|
hostCoverageScope: EXAMPLE_HOST_COVERAGE_SCOPE,
|
|
108
108
|
jurisdiction: EXAMPLE_JURISDICTION,
|
|
109
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Host route segment used in `/host/cds-{hostCoverageScope}/v1/{hostNetwork}/...`.
|
|
111
|
+
*
|
|
112
|
+
* This is intentionally not the tenant business sector.
|
|
113
|
+
*/
|
|
114
|
+
hostNetwork: EXAMPLE_NETWORK_TYPE,
|
|
115
|
+
/** @deprecated Use `hostNetwork`. */
|
|
116
|
+
sector: EXAMPLE_NETWORK_TYPE,
|
|
110
117
|
};
|
|
111
118
|
export const EXAMPLE_CONTROLLER_DID = 'did:web:people.acme.org:controllers:primary';
|
|
112
119
|
export const EXAMPLE_CONTROLLER_EMAIL = EXAMPLE_EMAIL_CONTROLLER_ORG;
|
|
@@ -67,7 +67,7 @@ export interface BuildDidcommPlaintextTransportMetadataInput {
|
|
|
67
67
|
* Optional explicit content type copied into the mirrored technical JWS
|
|
68
68
|
* header.
|
|
69
69
|
*
|
|
70
|
-
* Defaults to `application/didcomm-
|
|
70
|
+
* Defaults to `application/didcomm-plain+json`.
|
|
71
71
|
*/
|
|
72
72
|
contentType?: string;
|
|
73
73
|
}
|
|
@@ -103,7 +103,7 @@ export declare function buildOrganizationBindingInput(input: BuildOrganizationBi
|
|
|
103
103
|
* Transport rule:
|
|
104
104
|
* - in secure JOSE transport, these values belong in the protected JWS/JWE
|
|
105
105
|
* headers of the real envelope
|
|
106
|
-
* - in `application/didcomm-
|
|
106
|
+
* - in `application/didcomm-plain+json`, there is no signed outer
|
|
107
107
|
* envelope on the wire, so high-level SDK/BFF helpers may mirror the same
|
|
108
108
|
* technical key identifiers and public JWKs into `meta.jws.protected` and
|
|
109
109
|
* `meta.jwe.header`
|
|
@@ -122,7 +122,7 @@ export declare function buildDidcommPlaintextTransportMetadata(input: BuildDidco
|
|
|
122
122
|
* Transport note:
|
|
123
123
|
* - secure JOSE submission should place technical signing/encryption metadata
|
|
124
124
|
* in the protected headers of the real JWS/JWE envelope
|
|
125
|
-
* - demo `application/didcomm-
|
|
125
|
+
* - demo `application/didcomm-plain+json` flows may mirror those same
|
|
126
126
|
* values into plaintext `meta.jws.protected` / `meta.jwe.header` as a
|
|
127
127
|
* technical fallback expected by GW-compatible backends
|
|
128
128
|
* - that plaintext transport metadata must not replace the canonical
|
|
@@ -77,7 +77,7 @@ export function buildOrganizationBindingInput(input) {
|
|
|
77
77
|
* Transport rule:
|
|
78
78
|
* - in secure JOSE transport, these values belong in the protected JWS/JWE
|
|
79
79
|
* headers of the real envelope
|
|
80
|
-
* - in `application/didcomm-
|
|
80
|
+
* - in `application/didcomm-plain+json`, there is no signed outer
|
|
81
81
|
* envelope on the wire, so high-level SDK/BFF helpers may mirror the same
|
|
82
82
|
* technical key identifiers and public JWKs into `meta.jws.protected` and
|
|
83
83
|
* `meta.jwe.header`
|
|
@@ -98,7 +98,7 @@ export function buildDidcommPlaintextTransportMetadata(input) {
|
|
|
98
98
|
protected: {
|
|
99
99
|
alg: String(signingKey.alg || '').trim() || 'none',
|
|
100
100
|
kid: String(signingKey.kid || '').trim() || 'none',
|
|
101
|
-
cty: String(input.contentType || '').trim() || 'application/didcomm-
|
|
101
|
+
cty: String(input.contentType || '').trim() || 'application/didcomm-plain+json',
|
|
102
102
|
jwk: signingKey,
|
|
103
103
|
},
|
|
104
104
|
},
|
|
@@ -128,7 +128,7 @@ export function buildDidcommPlaintextTransportMetadata(input) {
|
|
|
128
128
|
* Transport note:
|
|
129
129
|
* - secure JOSE submission should place technical signing/encryption metadata
|
|
130
130
|
* in the protected headers of the real JWS/JWE envelope
|
|
131
|
-
* - demo `application/didcomm-
|
|
131
|
+
* - demo `application/didcomm-plain+json` flows may mirror those same
|
|
132
132
|
* values into plaintext `meta.jws.protected` / `meta.jwe.header` as a
|
|
133
133
|
* technical fallback expected by GW-compatible backends
|
|
134
134
|
* - that plaintext transport metadata must not replace the canonical
|
|
@@ -84,3 +84,5 @@ export declare class BundleReader {
|
|
|
84
84
|
private buildSeverityBucket;
|
|
85
85
|
private resolveEntryIdentifier;
|
|
86
86
|
}
|
|
87
|
+
export declare function unwrapBundleLikeResponseBody(input: unknown): Record<string, unknown>;
|
|
88
|
+
export declare function readFirstBundleResourceFromResponseBody(input: unknown): Record<string, unknown> | undefined;
|
|
@@ -221,3 +221,17 @@ export class BundleReader {
|
|
|
221
221
|
function normalizeOptionalString(value) {
|
|
222
222
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
223
223
|
}
|
|
224
|
+
export function unwrapBundleLikeResponseBody(input) {
|
|
225
|
+
const body = input && typeof input === 'object' ? input : {};
|
|
226
|
+
const nested = body.body && typeof body.body === 'object' ? body.body : undefined;
|
|
227
|
+
const candidate = nested && (Array.isArray(nested.data) || Array.isArray(nested.entry))
|
|
228
|
+
? nested
|
|
229
|
+
: body;
|
|
230
|
+
return candidate && typeof candidate === 'object' ? candidate : {};
|
|
231
|
+
}
|
|
232
|
+
export function readFirstBundleResourceFromResponseBody(input) {
|
|
233
|
+
const reader = new BundleReader(unwrapBundleLikeResponseBody(input));
|
|
234
|
+
const first = reader.getEntries()[0];
|
|
235
|
+
const resource = first?.resource;
|
|
236
|
+
return resource && typeof resource === 'object' ? resource : undefined;
|
|
237
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClinicalResourceBundleLike } from './clinical-resource-view.js';
|
|
2
|
+
export type ClinicalBundleTypeSummary = Readonly<{
|
|
3
|
+
resourceType: string;
|
|
4
|
+
count: number;
|
|
5
|
+
}>;
|
|
6
|
+
export type ClinicalBundleSummary = Readonly<{
|
|
7
|
+
totalEntries: number;
|
|
8
|
+
resourceTypes: ClinicalBundleTypeSummary[];
|
|
9
|
+
xhtmlEntries: number;
|
|
10
|
+
notedEntries: number;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Builds one high-level summary from a FHIR/IPS bundle already normalized to
|
|
14
|
+
* the common clinical-resource view contract.
|
|
15
|
+
*
|
|
16
|
+
* Intended for BFF/frontend/call-center code that needs to announce simple
|
|
17
|
+
* menu facts such as "how many medications are present" without hand-reading
|
|
18
|
+
* bundle entries.
|
|
19
|
+
*/
|
|
20
|
+
export declare function summarizeClinicalBundle(bundle: ClinicalResourceBundleLike): ClinicalBundleSummary;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { toClinicalResourceExpandedViews } from './clinical-resource-view.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds one high-level summary from a FHIR/IPS bundle already normalized to
|
|
5
|
+
* the common clinical-resource view contract.
|
|
6
|
+
*
|
|
7
|
+
* Intended for BFF/frontend/call-center code that needs to announce simple
|
|
8
|
+
* menu facts such as "how many medications are present" without hand-reading
|
|
9
|
+
* bundle entries.
|
|
10
|
+
*/
|
|
11
|
+
export function summarizeClinicalBundle(bundle) {
|
|
12
|
+
const views = toClinicalResourceExpandedViews(bundle);
|
|
13
|
+
const counts = new Map();
|
|
14
|
+
let xhtmlEntries = 0;
|
|
15
|
+
let notedEntries = 0;
|
|
16
|
+
views.forEach((view) => {
|
|
17
|
+
const resourceType = String(view.common.resourceType || 'Unknown').trim() || 'Unknown';
|
|
18
|
+
counts.set(resourceType, (counts.get(resourceType) || 0) + 1);
|
|
19
|
+
if (String(view.xhtml || '').trim()) {
|
|
20
|
+
xhtmlEntries += 1;
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(view.notes) && view.notes.length > 0) {
|
|
23
|
+
notedEntries += 1;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
totalEntries: views.length,
|
|
28
|
+
resourceTypes: [...counts.entries()]
|
|
29
|
+
.map(([resourceType, count]) => ({ resourceType, count }))
|
|
30
|
+
.sort((left, right) => left.resourceType.localeCompare(right.resourceType)),
|
|
31
|
+
xhtmlEntries,
|
|
32
|
+
notedEntries,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare const DIDCOMM_COMMUNICATION_MODES: Readonly<{
|
|
2
|
+
readonly Plain: "plain";
|
|
3
|
+
readonly Strict: "strict";
|
|
4
|
+
readonly AutoDetect: "auto-detect";
|
|
5
|
+
}>;
|
|
6
|
+
export type CommunicationMode = typeof DIDCOMM_COMMUNICATION_MODES[keyof typeof DIDCOMM_COMMUNICATION_MODES];
|
|
7
|
+
export declare const DIDCOMM_SUBMIT_KINDS: Readonly<{
|
|
8
|
+
readonly Plain: "plain";
|
|
9
|
+
readonly Encrypted: "encrypted";
|
|
10
|
+
}>;
|
|
11
|
+
export type DidcommSubmitKind = typeof DIDCOMM_SUBMIT_KINDS[keyof typeof DIDCOMM_SUBMIT_KINDS];
|
|
2
12
|
export type DidcommSubmissionCapabilities = {
|
|
3
13
|
hasRecipientEncryptionJwk: boolean;
|
|
4
14
|
};
|
|
15
|
+
export declare const DIDCOMM_SUBMISSION_REASONS: Readonly<{
|
|
16
|
+
readonly PlainMode: "plain-mode";
|
|
17
|
+
readonly StrictMode: "strict-mode";
|
|
18
|
+
readonly AutoDetectEncrypted: "auto-detect-encrypted";
|
|
19
|
+
readonly AutoDetectPlain: "auto-detect-plain";
|
|
20
|
+
}>;
|
|
21
|
+
export type DidcommSubmissionReason = typeof DIDCOMM_SUBMISSION_REASONS[keyof typeof DIDCOMM_SUBMISSION_REASONS];
|
|
5
22
|
export type DidcommSubmissionPlan = {
|
|
6
23
|
mode: CommunicationMode;
|
|
7
|
-
submitKind:
|
|
8
|
-
reason:
|
|
24
|
+
submitKind: DidcommSubmitKind;
|
|
25
|
+
reason: DidcommSubmissionReason;
|
|
9
26
|
};
|
|
10
27
|
export declare function resolveDidcommSubmissionPlan(mode: CommunicationMode, capabilities: DidcommSubmissionCapabilities): DidcommSubmissionPlan;
|
|
@@ -1,15 +1,46 @@
|
|
|
1
|
+
export const DIDCOMM_COMMUNICATION_MODES = Object.freeze({
|
|
2
|
+
Plain: 'plain',
|
|
3
|
+
Strict: 'strict',
|
|
4
|
+
AutoDetect: 'auto-detect',
|
|
5
|
+
});
|
|
6
|
+
export const DIDCOMM_SUBMIT_KINDS = Object.freeze({
|
|
7
|
+
Plain: 'plain',
|
|
8
|
+
Encrypted: 'encrypted',
|
|
9
|
+
});
|
|
10
|
+
export const DIDCOMM_SUBMISSION_REASONS = Object.freeze({
|
|
11
|
+
PlainMode: 'plain-mode',
|
|
12
|
+
StrictMode: 'strict-mode',
|
|
13
|
+
AutoDetectEncrypted: 'auto-detect-encrypted',
|
|
14
|
+
AutoDetectPlain: 'auto-detect-plain',
|
|
15
|
+
});
|
|
1
16
|
export function resolveDidcommSubmissionPlan(mode, capabilities) {
|
|
2
|
-
if (mode ===
|
|
3
|
-
return {
|
|
17
|
+
if (mode === DIDCOMM_COMMUNICATION_MODES.Plain) {
|
|
18
|
+
return {
|
|
19
|
+
mode,
|
|
20
|
+
submitKind: DIDCOMM_SUBMIT_KINDS.Plain,
|
|
21
|
+
reason: DIDCOMM_SUBMISSION_REASONS.PlainMode,
|
|
22
|
+
};
|
|
4
23
|
}
|
|
5
|
-
if (mode ===
|
|
24
|
+
if (mode === DIDCOMM_COMMUNICATION_MODES.Strict) {
|
|
6
25
|
if (!capabilities.hasRecipientEncryptionJwk) {
|
|
7
26
|
throw new Error('strict mode requires recipient encryption JWK.');
|
|
8
27
|
}
|
|
9
|
-
return {
|
|
28
|
+
return {
|
|
29
|
+
mode,
|
|
30
|
+
submitKind: DIDCOMM_SUBMIT_KINDS.Encrypted,
|
|
31
|
+
reason: DIDCOMM_SUBMISSION_REASONS.StrictMode,
|
|
32
|
+
};
|
|
10
33
|
}
|
|
11
34
|
if (capabilities.hasRecipientEncryptionJwk) {
|
|
12
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
mode,
|
|
37
|
+
submitKind: DIDCOMM_SUBMIT_KINDS.Encrypted,
|
|
38
|
+
reason: DIDCOMM_SUBMISSION_REASONS.AutoDetectEncrypted,
|
|
39
|
+
};
|
|
13
40
|
}
|
|
14
|
-
return {
|
|
41
|
+
return {
|
|
42
|
+
mode,
|
|
43
|
+
submitKind: DIDCOMM_SUBMIT_KINDS.Plain,
|
|
44
|
+
reason: DIDCOMM_SUBMISSION_REASONS.AutoDetectPlain,
|
|
45
|
+
};
|
|
15
46
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { CommunicationMode } from './didcomm-submit-policy';
|
|
1
|
+
import { CommunicationMode, type DidcommSubmitKind } from './didcomm-submit-policy';
|
|
2
|
+
export declare const DIDCOMM_PLAINTEXT_JSON_MEDIA_TYPE: "application/didcomm-plain+json";
|
|
3
|
+
export declare const DIDCOMM_ENCRYPTED_JSON_MEDIA_TYPE: "application/didcomm-encrypted+json";
|
|
4
|
+
export declare const DIDCOMM_DEFAULT_ACCEPT_HEADER: "application/json, application/didcomm-plain+json, */*";
|
|
5
|
+
export declare const DIDCOMM_CONTENT_TYPE_BY_SUBMIT_KIND: Readonly<{
|
|
6
|
+
readonly plain: "application/didcomm-plain+json";
|
|
7
|
+
readonly encrypted: "application/didcomm-encrypted+json";
|
|
8
|
+
}>;
|
|
2
9
|
export type DidcommFetchInit = {
|
|
3
10
|
method: 'POST';
|
|
4
11
|
headers: Record<string, string>;
|
|
@@ -28,8 +35,8 @@ export type DidcommSubmitResult = {
|
|
|
28
35
|
status: number;
|
|
29
36
|
location?: string;
|
|
30
37
|
body: unknown;
|
|
31
|
-
submitKind:
|
|
32
|
-
contentType:
|
|
38
|
+
submitKind: DidcommSubmitKind;
|
|
39
|
+
contentType: typeof DIDCOMM_PLAINTEXT_JSON_MEDIA_TYPE | typeof DIDCOMM_ENCRYPTED_JSON_MEDIA_TYPE;
|
|
33
40
|
};
|
|
34
41
|
/**
|
|
35
42
|
* Submits a DIDComm payload using either plaintext or encrypted transport,
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { resolveDidcommSubmissionPlan } from './didcomm-submit-policy.js';
|
|
1
|
+
import { DIDCOMM_SUBMIT_KINDS, resolveDidcommSubmissionPlan, } from './didcomm-submit-policy.js';
|
|
2
|
+
export const DIDCOMM_PLAINTEXT_JSON_MEDIA_TYPE = 'application/didcomm-plain+json';
|
|
3
|
+
export const DIDCOMM_ENCRYPTED_JSON_MEDIA_TYPE = 'application/didcomm-encrypted+json';
|
|
4
|
+
export const DIDCOMM_DEFAULT_ACCEPT_HEADER = `application/json, ${DIDCOMM_PLAINTEXT_JSON_MEDIA_TYPE}, */*`;
|
|
5
|
+
export const DIDCOMM_CONTENT_TYPE_BY_SUBMIT_KIND = Object.freeze({
|
|
6
|
+
[DIDCOMM_SUBMIT_KINDS.Plain]: DIDCOMM_PLAINTEXT_JSON_MEDIA_TYPE,
|
|
7
|
+
[DIDCOMM_SUBMIT_KINDS.Encrypted]: DIDCOMM_ENCRYPTED_JSON_MEDIA_TYPE,
|
|
8
|
+
});
|
|
2
9
|
function getHeaderValue(headers, name) {
|
|
3
10
|
if (!headers || typeof headers.get !== 'function') {
|
|
4
11
|
return undefined;
|
|
@@ -40,12 +47,12 @@ export async function submitDidcomm(input) {
|
|
|
40
47
|
});
|
|
41
48
|
const headers = {
|
|
42
49
|
...(input.defaultHeaders ?? {}),
|
|
43
|
-
Accept:
|
|
50
|
+
Accept: DIDCOMM_DEFAULT_ACCEPT_HEADER,
|
|
44
51
|
};
|
|
45
52
|
let body;
|
|
46
53
|
let contentType;
|
|
47
|
-
if (plan.submitKind ===
|
|
48
|
-
contentType =
|
|
54
|
+
if (plan.submitKind === DIDCOMM_SUBMIT_KINDS.Plain) {
|
|
55
|
+
contentType = DIDCOMM_CONTENT_TYPE_BY_SUBMIT_KIND[DIDCOMM_SUBMIT_KINDS.Plain];
|
|
49
56
|
body = JSON.stringify(input.payload);
|
|
50
57
|
}
|
|
51
58
|
else {
|
|
@@ -60,7 +67,7 @@ export async function submitDidcomm(input) {
|
|
|
60
67
|
}
|
|
61
68
|
const compactJws = await input.signCompactJws(input.payload);
|
|
62
69
|
body = await input.encryptCompactJwe(compactJws, input.recipientEncryptionJwk);
|
|
63
|
-
contentType =
|
|
70
|
+
contentType = DIDCOMM_CONTENT_TYPE_BY_SUBMIT_KIND[DIDCOMM_SUBMIT_KINDS.Encrypted];
|
|
64
71
|
}
|
|
65
72
|
headers['Content-Type'] = contentType;
|
|
66
73
|
if (input.bearerToken) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type FamilyRegistrationStatus = 'new_created' | 'resume_required' | 'already_exists' | 'not_found';
|
|
2
|
+
export type FamilyOrganizationSubjectInfo = Readonly<{
|
|
3
|
+
identifierType?: string;
|
|
4
|
+
identifierValue?: string;
|
|
5
|
+
alternateName?: string;
|
|
6
|
+
birthDate?: string;
|
|
7
|
+
ownerTelephone?: string;
|
|
8
|
+
}>;
|
|
9
|
+
export type FamilyOrganizationSummary = Readonly<{
|
|
10
|
+
status: FamilyRegistrationStatus;
|
|
11
|
+
offerId?: string;
|
|
12
|
+
organizationId?: string;
|
|
13
|
+
subjectInfo?: FamilyOrganizationSubjectInfo;
|
|
14
|
+
missingFields?: string[];
|
|
15
|
+
updatedAt?: string;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Reads the first family-organization summary returned by current GW-style
|
|
19
|
+
* search or batch responses.
|
|
20
|
+
*
|
|
21
|
+
* Returns `null` when the response does not contain one usable summary or when
|
|
22
|
+
* the registration status is explicitly `not_found`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readFamilyOrganizationSummaryFromResponseBody(body: unknown): FamilyOrganizationSummary | null;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
function asRecord(value) {
|
|
3
|
+
return value && typeof value === 'object' ? value : {};
|
|
4
|
+
}
|
|
5
|
+
function normalizeText(value) {
|
|
6
|
+
const normalized = String(value ?? '').trim();
|
|
7
|
+
return normalized || undefined;
|
|
8
|
+
}
|
|
9
|
+
function normalizeStringList(value) {
|
|
10
|
+
if (!Array.isArray(value)) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const items = value.map((item) => normalizeText(item)).filter(Boolean);
|
|
14
|
+
return items.length ? items : undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reads the first family-organization summary returned by current GW-style
|
|
18
|
+
* search or batch responses.
|
|
19
|
+
*
|
|
20
|
+
* Returns `null` when the response does not contain one usable summary or when
|
|
21
|
+
* the registration status is explicitly `not_found`.
|
|
22
|
+
*/
|
|
23
|
+
export function readFamilyOrganizationSummaryFromResponseBody(body) {
|
|
24
|
+
const root = asRecord(body);
|
|
25
|
+
const bodyNode = asRecord(root.body);
|
|
26
|
+
const rawEntries = Array.isArray(bodyNode.data)
|
|
27
|
+
? bodyNode.data
|
|
28
|
+
: (Array.isArray(root.data) ? root.data : []);
|
|
29
|
+
const firstEntry = rawEntries[0];
|
|
30
|
+
if (!firstEntry || typeof firstEntry !== 'object') {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const entry = asRecord(firstEntry);
|
|
34
|
+
const entryMeta = asRecord(entry.meta);
|
|
35
|
+
const entryResource = asRecord(entry.resource);
|
|
36
|
+
const entryResourceMeta = asRecord(entryResource.meta);
|
|
37
|
+
const claims = {
|
|
38
|
+
...asRecord(entryMeta.claims),
|
|
39
|
+
...asRecord(entryResourceMeta.claims),
|
|
40
|
+
};
|
|
41
|
+
const status = normalizeText(claims['org.schema.FamilyRegistration.status'] ?? claims.status);
|
|
42
|
+
if (!status || status === 'not_found') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
status,
|
|
47
|
+
offerId: normalizeText(claims['org.schema.Offer.identifier']),
|
|
48
|
+
organizationId: normalizeText(claims['org.schema.Organization.identifier.value'] ?? entryResource.id),
|
|
49
|
+
subjectInfo: {
|
|
50
|
+
identifierType: normalizeText(claims['org.schema.Organization.identifier.additionalType']),
|
|
51
|
+
identifierValue: normalizeText(claims['org.schema.Organization.identifier.value']),
|
|
52
|
+
alternateName: normalizeText(claims['org.schema.Organization.alternateName']),
|
|
53
|
+
birthDate: normalizeText(claims['org.schema.Organization.foundingDate']),
|
|
54
|
+
ownerTelephone: normalizeText(claims['org.schema.Organization.owner.telephone']),
|
|
55
|
+
},
|
|
56
|
+
missingFields: normalizeStringList(claims['org.schema.FamilyRegistration.missingFields'] ?? claims.missingFields),
|
|
57
|
+
updatedAt: normalizeText(claims['org.schema.FamilyRegistration.updatedAt'] ?? claims.updatedAt),
|
|
58
|
+
};
|
|
59
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export * from './discovery-normalization';
|
|
|
28
28
|
export * from './format-converter';
|
|
29
29
|
export * from './fhir-cid';
|
|
30
30
|
export * from './fhir-search';
|
|
31
|
+
export * from './family-organization-summary';
|
|
31
32
|
export * from './gw-core-path';
|
|
32
33
|
export * from './communication-fhir-r4';
|
|
33
34
|
export * from './communication-document-reference';
|
|
@@ -41,13 +42,16 @@ export * from './communication-attached-bundle-session';
|
|
|
41
42
|
export * from './confidential-storage-persistence';
|
|
42
43
|
export * from './confidential-storage-test-data';
|
|
43
44
|
export * from './permission-templates';
|
|
45
|
+
export * from './professional-smart';
|
|
44
46
|
export * from './related-person-list';
|
|
45
47
|
export * from './clinical-resource-converters';
|
|
48
|
+
export * from './clinical-bundle-summary';
|
|
46
49
|
export * from './clinical-resource-view';
|
|
47
50
|
export * from './fhir-validator';
|
|
48
51
|
export * from './family-registration-test-data';
|
|
49
52
|
export * from './individual-form-pdf';
|
|
50
53
|
export * from './individual-organization-claims';
|
|
54
|
+
export * from './legal-organization-onboarding-editor';
|
|
51
55
|
export * from './organization-lifecycle';
|
|
52
56
|
export * from './organization-did-binding';
|
|
53
57
|
export * from './individual-organization-lifecycle';
|
package/dist/utils/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export * from './discovery-normalization.js';
|
|
|
28
28
|
export * from './format-converter.js';
|
|
29
29
|
export * from './fhir-cid.js';
|
|
30
30
|
export * from './fhir-search.js';
|
|
31
|
+
export * from './family-organization-summary.js';
|
|
31
32
|
export * from './gw-core-path.js';
|
|
32
33
|
export * from './communication-fhir-r4.js';
|
|
33
34
|
export * from './communication-document-reference.js';
|
|
@@ -41,13 +42,16 @@ export * from './communication-attached-bundle-session.js';
|
|
|
41
42
|
export * from './confidential-storage-persistence.js';
|
|
42
43
|
export * from './confidential-storage-test-data.js';
|
|
43
44
|
export * from './permission-templates.js';
|
|
45
|
+
export * from './professional-smart.js';
|
|
44
46
|
export * from './related-person-list.js';
|
|
45
47
|
export * from './clinical-resource-converters.js';
|
|
48
|
+
export * from './clinical-bundle-summary.js';
|
|
46
49
|
export * from './clinical-resource-view.js';
|
|
47
50
|
export * from './fhir-validator.js';
|
|
48
51
|
export * from './family-registration-test-data.js';
|
|
49
52
|
export * from './individual-form-pdf.js';
|
|
50
53
|
export * from './individual-organization-claims.js';
|
|
54
|
+
export * from './legal-organization-onboarding-editor.js';
|
|
51
55
|
export * from './organization-lifecycle.js';
|
|
52
56
|
export * from './organization-did-binding.js';
|
|
53
57
|
export * from './individual-organization-lifecycle.js';
|