gdc-common-utils-ts 2.0.1 → 2.0.4
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/examples/ica-verify-response.d.ts +230 -0
- package/dist/examples/ica-verify-response.js +263 -0
- package/dist/examples/index.d.ts +3 -0
- package/dist/examples/index.js +3 -0
- package/dist/examples/legal-organization-verification-transaction.d.ts +1 -0
- package/dist/examples/legal-organization-verification-transaction.js +66 -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 +3 -0
- package/dist/examples/shared.js +3 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/legal-organization-verification-transaction.d.ts +90 -0
- package/dist/utils/legal-organization-verification-transaction.js +65 -0
- package/dist/utils/organization-did-binding.d.ts +60 -0
- package/dist/utils/organization-did-binding.js +103 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,26 @@ Short rule:
|
|
|
10
10
|
- do not add ad hoc literals in `101` tests when `gdc-common-utils-ts` can own
|
|
11
11
|
the reusable value instead
|
|
12
12
|
|
|
13
|
+
## Shared Workspace
|
|
14
|
+
|
|
15
|
+
Recommended local layout for the shared ICA/GDC repos and fixture PDFs:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
~/GITS/gdc-workspace/
|
|
19
|
+
dataspace-ica-ts/
|
|
20
|
+
ica-client-sdk-ts/
|
|
21
|
+
gdc-common-utils-ts/
|
|
22
|
+
examples/
|
|
23
|
+
<example-pdf-1>.pdf
|
|
24
|
+
<example-pdf-2>.pdf
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This is recommended because:
|
|
28
|
+
|
|
29
|
+
- cross-repo docs and fixture-based tests often refer to sibling repos
|
|
30
|
+
- real PDF examples are expected under `~/GITS/gdc-workspace/examples/`
|
|
31
|
+
- keeping a single shared workspace reduces path drift between repos
|
|
32
|
+
|
|
13
33
|
Employee shared examples live in `src/examples/employee.ts`.
|
|
14
34
|
Employee pure helper functions live in `src/utils/employee.ts`.
|
|
15
35
|
|
|
@@ -61,6 +81,31 @@ They are not interchangeable:
|
|
|
61
81
|
Production-grade flows should prefer ICA-issued representative VCs that carry
|
|
62
82
|
both dimensions.
|
|
63
83
|
|
|
84
|
+
## Legal Organization Verification Transaction
|
|
85
|
+
|
|
86
|
+
The first host-side legal-organization onboarding step now has one canonical
|
|
87
|
+
shared payload builder in this package:
|
|
88
|
+
|
|
89
|
+
- `buildLegalOrganizationVerificationTransactionBundle(...)`
|
|
90
|
+
- `EXAMPLE_LEGAL_ORGANIZATION_VERIFICATION_TRANSACTION_BUNDLE`
|
|
91
|
+
|
|
92
|
+
This builder owns the business payload only:
|
|
93
|
+
|
|
94
|
+
- signed PDF evidence attachment references
|
|
95
|
+
- `controller.publicKeyJwk` as the controller business binding key
|
|
96
|
+
- optional `organization.publicKeyJwk`
|
|
97
|
+
- legal representative payload
|
|
98
|
+
- `meta.claims` business claims
|
|
99
|
+
|
|
100
|
+
It intentionally does not own:
|
|
101
|
+
|
|
102
|
+
- `fetch`
|
|
103
|
+
- polling
|
|
104
|
+
- JOSE transport execution
|
|
105
|
+
- BFF/frontend runtime crypto
|
|
106
|
+
|
|
107
|
+
Those runtime concerns belong in `gdc-sdk-node-ts`, `gdc-sdk-front-ts`, or GW.
|
|
108
|
+
|
|
64
109
|
Step by step:
|
|
65
110
|
|
|
66
111
|
1. ICA verifies the signed PDF and emits the representative VC.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { EXAMPLE_BUNDLE_RESOURCE_TYPE } from './shared';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal DIDComm bundle attachment example shape reused by ICA response fixtures.
|
|
4
|
+
*/
|
|
5
|
+
export interface IcaVerifyResponseExampleAttachment {
|
|
6
|
+
id: string;
|
|
7
|
+
format: string;
|
|
8
|
+
media_type: string;
|
|
9
|
+
filename: string;
|
|
10
|
+
data: {
|
|
11
|
+
json: {
|
|
12
|
+
format: string;
|
|
13
|
+
jwt: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Minimal OperationOutcome issue example shape reused by ICA response fixtures.
|
|
19
|
+
*/
|
|
20
|
+
export interface IcaVerifyResponseExampleIssue {
|
|
21
|
+
severity: 'information' | 'warning' | 'error' | 'fatal';
|
|
22
|
+
code: string;
|
|
23
|
+
diagnostics: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Minimal OperationOutcome example shape reused by ICA response fixtures.
|
|
27
|
+
*/
|
|
28
|
+
export interface IcaVerifyResponseExampleOutcome {
|
|
29
|
+
resourceType: typeof EXAMPLE_VERIFY_RESPONSE_OPERATION_OUTCOME_RESOURCE_TYPE;
|
|
30
|
+
issue: IcaVerifyResponseExampleIssue[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Canonical example of the `_verify-response` DIDComm payload emitted by ICA.
|
|
34
|
+
*
|
|
35
|
+
* This example is intentionally transport-neutral and reusable by:
|
|
36
|
+
* - Swagger/OpenAPI examples
|
|
37
|
+
* - SDK unit tests
|
|
38
|
+
* - portal/BFF documentation
|
|
39
|
+
*
|
|
40
|
+
* Contract notes:
|
|
41
|
+
* - `body.data[0]` carries the organization credential plus optional generated
|
|
42
|
+
* organization signing keypair
|
|
43
|
+
* - `body.data[1]` carries the legal representative credential plus the
|
|
44
|
+
* controller binding public key
|
|
45
|
+
* - `credentialSubject.sameAs` expresses public identity continuity
|
|
46
|
+
* - `credentialSubject.hasCredential.material` expresses controller
|
|
47
|
+
* signing/binding key continuity as an RFC 9278 JWK-thumbprint URN
|
|
48
|
+
*/
|
|
49
|
+
export interface IcaVerifyTermsResponseExample {
|
|
50
|
+
jti: string;
|
|
51
|
+
iss: string;
|
|
52
|
+
aud: string;
|
|
53
|
+
thid: string;
|
|
54
|
+
type: string;
|
|
55
|
+
attachments: IcaVerifyResponseExampleAttachment[];
|
|
56
|
+
body: {
|
|
57
|
+
resourceType: typeof EXAMPLE_BUNDLE_RESOURCE_TYPE;
|
|
58
|
+
type: typeof EXAMPLE_VERIFY_RESPONSE_BATCH_RESPONSE_TYPE;
|
|
59
|
+
total: number;
|
|
60
|
+
issues: IcaVerifyResponseExampleOutcome;
|
|
61
|
+
data: Array<Record<string, unknown>>;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_OPERATION_OUTCOME_RESOURCE_TYPE: "OperationOutcome";
|
|
65
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_BATCH_RESPONSE_TYPE: "batch-response";
|
|
66
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_SCHEMA_ORG_CONTEXT: "https://schema.org";
|
|
67
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_TYPE: "Person";
|
|
68
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORGANIZATION_TYPE: "Organization";
|
|
69
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_JTI: "urn:uuid:verify-resp-001";
|
|
70
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_THID: "verify-terms-001";
|
|
71
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_BUNDLE_TYPE: "application/bundle-api+json";
|
|
72
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_DATE: "2026-03-12T21:12:26.646Z";
|
|
73
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PROOF_DATE: "2026-03-12T21:12:57.534Z";
|
|
74
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_VERSION_ID: "zPdfVersionHash001";
|
|
75
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_VC_ID: "urn:uuid:org-vc-001";
|
|
76
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_VC_ID: "urn:uuid:person-vc-001";
|
|
77
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_ENTRY_TYPE: "Organization-verification-v1.0";
|
|
78
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ENTRY_TYPE: "LegalRepresentative-verification-v1.0";
|
|
79
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT_ID: "vc-jwt-1";
|
|
80
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT_ID: "vc-jwt-2";
|
|
81
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT_FILENAME: "Organization-verification-v1.0-1.jwt";
|
|
82
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT_FILENAME: "LegalRepresentative-verification-v1.0-2.jwt";
|
|
83
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_JWT: "<vc-jwt-organization>";
|
|
84
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_JWT: "<vc-jwt-legal-representative>";
|
|
85
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_MEDIA_TYPE: "application/vc+jwt";
|
|
86
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ATTACHMENT_FORMAT: "vc+jwt";
|
|
87
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_STATUS_OK: "200";
|
|
88
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_KID: "org-es384-001";
|
|
89
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_KID: "controller-es384-001";
|
|
90
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_DID: "did:web:globaldatacare.es:onehealth:organization:taxid:VATES-B00112233";
|
|
91
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_NAME: "Alex Example";
|
|
92
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_GIVEN_NAME: "Alex";
|
|
93
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_FAMILY_NAME: "Example";
|
|
94
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_NATIONALITY: "ES";
|
|
95
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ADDITIONAL_TYPE: "ES384";
|
|
96
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ALTERNATE_NAME: "controller-es384-001";
|
|
97
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_ADDITIONAL_TYPE: "sector=onehealth;section=dataprovider;kind=clinic;action=_index-provider,_research-provider";
|
|
98
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ADDRESS_TYPE: "PostalAddress";
|
|
99
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ADDRESS_COUNTRY: "ES";
|
|
100
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_OCCUPATION_TYPE: "Occupation";
|
|
101
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_OCCUPATION_NAME: "LegalRepresentative";
|
|
102
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_OCCUPATION_IDENTIFIER: "urn:ilo:ilostat:isco-08:1120";
|
|
103
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PROOF_TYPE: "JsonWebSignature2020";
|
|
104
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PROOF_PURPOSE: "assertionMethod";
|
|
105
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PROOF_VERIFICATION_METHOD: "did:web:localhost%3A3310#verification-key-001";
|
|
106
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_PROOF_JWS: "<detached-jws-organization-truncated>";
|
|
107
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_PROOF_JWS: "<detached-jws-person-truncated>";
|
|
108
|
+
/**
|
|
109
|
+
* Shared success outcome reused at bundle level and item level.
|
|
110
|
+
*/
|
|
111
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_SUCCESS_OUTCOME: IcaVerifyResponseExampleOutcome;
|
|
112
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_ITEM_OUTCOME: IcaVerifyResponseExampleOutcome;
|
|
113
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ITEM_OUTCOME: IcaVerifyResponseExampleOutcome;
|
|
114
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_PUBLIC_KEY_JWK: Readonly<{
|
|
115
|
+
kty: "EC";
|
|
116
|
+
crv: "P-384";
|
|
117
|
+
x: "org-pub-x";
|
|
118
|
+
y: "org-pub-y";
|
|
119
|
+
alg: "ES384";
|
|
120
|
+
kid: "org-es384-001";
|
|
121
|
+
}>;
|
|
122
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_PRIVATE_KEY_JWK: Readonly<{
|
|
123
|
+
d: "org-priv-d";
|
|
124
|
+
kty: "EC";
|
|
125
|
+
crv: "P-384";
|
|
126
|
+
x: "org-pub-x";
|
|
127
|
+
y: "org-pub-y";
|
|
128
|
+
alg: "ES384";
|
|
129
|
+
kid: "org-es384-001";
|
|
130
|
+
}>;
|
|
131
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_PUBLIC_KEY_JWK: Readonly<{
|
|
132
|
+
kty: "EC";
|
|
133
|
+
crv: "P-384";
|
|
134
|
+
x: "controller-x";
|
|
135
|
+
y: "controller-y";
|
|
136
|
+
alg: "ES384";
|
|
137
|
+
kid: "controller-es384-001";
|
|
138
|
+
}>;
|
|
139
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_AUTHORIZED_CATEGORY: "health-care";
|
|
140
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL: Readonly<{
|
|
141
|
+
id: "urn:uuid:org-vc-001";
|
|
142
|
+
'@context': ("https://www.w3.org/ns/credentials/v2" | "https://schema.org")[];
|
|
143
|
+
type: ("VerifiableCredential" | "OrganizationCredential")[];
|
|
144
|
+
issuer: "did:web:ica.example.org";
|
|
145
|
+
validFrom: "2026-03-12T21:12:26.646Z";
|
|
146
|
+
meta: {
|
|
147
|
+
versionId: "zPdfVersionHash001";
|
|
148
|
+
};
|
|
149
|
+
credentialSubject: {
|
|
150
|
+
id: "did:web:globaldatacare.es:onehealth:organization:taxid:VATES-B00112233";
|
|
151
|
+
'@type': "Organization";
|
|
152
|
+
legalName: "ACME Health Provider";
|
|
153
|
+
taxID: "VATES-B00112233";
|
|
154
|
+
sameAs: "did:web:provider.example.org";
|
|
155
|
+
url: "health-care.provider.example.org";
|
|
156
|
+
alternateName: string;
|
|
157
|
+
additionalType: "sector=onehealth;section=dataprovider;kind=clinic;action=_index-provider,_research-provider";
|
|
158
|
+
makesOffer: {
|
|
159
|
+
'@type': string;
|
|
160
|
+
category: "health-care";
|
|
161
|
+
};
|
|
162
|
+
address: {
|
|
163
|
+
'@type': "PostalAddress";
|
|
164
|
+
addressCountry: "ES";
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
evidence: never[];
|
|
168
|
+
proof: {
|
|
169
|
+
type: "JsonWebSignature2020";
|
|
170
|
+
created: "2026-03-12T21:12:57.534Z";
|
|
171
|
+
proofPurpose: "assertionMethod";
|
|
172
|
+
verificationMethod: "did:web:localhost%3A3310#verification-key-001";
|
|
173
|
+
jws: "<detached-jws-organization-truncated>";
|
|
174
|
+
};
|
|
175
|
+
}>;
|
|
176
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_CREDENTIAL: Readonly<{
|
|
177
|
+
id: "urn:uuid:person-vc-001";
|
|
178
|
+
'@context': ("https://www.w3.org/ns/credentials/v2" | "https://schema.org")[];
|
|
179
|
+
type: ("VerifiableCredential" | "LegalRepresentativeCredential" | "PersonCredential")[];
|
|
180
|
+
issuer: "did:web:ica.example.org";
|
|
181
|
+
validFrom: "2026-03-12T21:12:26.646Z";
|
|
182
|
+
meta: {
|
|
183
|
+
versionId: "zPdfVersionHash001";
|
|
184
|
+
};
|
|
185
|
+
credentialSubject: {
|
|
186
|
+
id: "urn:person:identifier:IDCES-99999999R";
|
|
187
|
+
'@type': "Person";
|
|
188
|
+
name: "Alex Example";
|
|
189
|
+
givenName: "Alex";
|
|
190
|
+
familyName: "Example";
|
|
191
|
+
identifier: "IDCES-99999999R";
|
|
192
|
+
nationality: "ES";
|
|
193
|
+
sameAs: "urn:multibase:zControllerHash";
|
|
194
|
+
hasCredential: {
|
|
195
|
+
material: "urn:ietf:params:oauth:jwk-thumbprint:sha-256:Q0ZfM0V4YW1wbGVUaHVtYnByaW50X2Jhc2U2NHVybA";
|
|
196
|
+
};
|
|
197
|
+
hasOccupation: {
|
|
198
|
+
'@type': "Occupation";
|
|
199
|
+
name: "LegalRepresentative";
|
|
200
|
+
identifier: "urn:ilo:ilostat:isco-08:1120";
|
|
201
|
+
};
|
|
202
|
+
memberOf: {
|
|
203
|
+
'@type': "Organization";
|
|
204
|
+
legalName: "ACME Health Provider";
|
|
205
|
+
taxID: "VATES-B00112233";
|
|
206
|
+
};
|
|
207
|
+
alternateName: "controller-es384-001";
|
|
208
|
+
additionalType: "ES384";
|
|
209
|
+
};
|
|
210
|
+
evidence: never[];
|
|
211
|
+
proof: {
|
|
212
|
+
type: "JsonWebSignature2020";
|
|
213
|
+
created: "2026-03-12T21:12:57.534Z";
|
|
214
|
+
proofPurpose: "assertionMethod";
|
|
215
|
+
verificationMethod: "did:web:localhost%3A3310#verification-key-001";
|
|
216
|
+
jws: "<detached-jws-person-truncated>";
|
|
217
|
+
};
|
|
218
|
+
}>;
|
|
219
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT: IcaVerifyResponseExampleAttachment;
|
|
220
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT: IcaVerifyResponseExampleAttachment;
|
|
221
|
+
/**
|
|
222
|
+
* Canonical `_verify-response` success example shared across ICA repos.
|
|
223
|
+
*/
|
|
224
|
+
export declare const EXAMPLE_ICA_VERIFY_TERMS_RESPONSE_SUCCESS: IcaVerifyTermsResponseExample;
|
|
225
|
+
/**
|
|
226
|
+
* Returns a detached deep clone of the canonical ICA `_verify-response`
|
|
227
|
+
* success example so tests/docs can tweak fields without mutating the shared
|
|
228
|
+
* frozen baseline.
|
|
229
|
+
*/
|
|
230
|
+
export declare function cloneIcaVerifyTermsResponseSuccessExample(): IcaVerifyTermsResponseExample;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
// Always create JSDoc, do not use strings inline in keys nor values, use types instead, and reuse the data test examples.
|
|
3
|
+
import { ActivationCredentialTypes, W3cCredentialContexts, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
|
|
4
|
+
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
5
|
+
import { DataspaceSectors } from '../constants/sectors.js';
|
|
6
|
+
import { IssueSeverity, IssueType } from '../models/issue.js';
|
|
7
|
+
import { EXAMPLE_DEFAULT_ICA_DID, EXAMPLE_BUNDLE_RESOURCE_TYPE, EXAMPLE_PROVIDER_DOMAIN, EXAMPLE_PROVIDER_LEGAL_NAME, EXAMPLE_PROVIDER_TAX_ID, EXAMPLE_TENANT_SERVICE_DID, } from './shared.js';
|
|
8
|
+
import { EXAMPLE_ORG_CONTROLLER_SIGNING_KEY_ID, EXAMPLE_REPRESENTATIVE_IDENTIFIER, EXAMPLE_REPRESENTATIVE_SAME_AS, EXAMPLE_REPRESENTATIVE_SUBJECT_URN, } from './ica-activation-proof.js';
|
|
9
|
+
export const EXAMPLE_VERIFY_RESPONSE_OPERATION_OUTCOME_RESOURCE_TYPE = 'OperationOutcome';
|
|
10
|
+
export const EXAMPLE_VERIFY_RESPONSE_BATCH_RESPONSE_TYPE = 'batch-response';
|
|
11
|
+
export const EXAMPLE_VERIFY_RESPONSE_SCHEMA_ORG_CONTEXT = 'https://schema.org';
|
|
12
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_TYPE = 'Person';
|
|
13
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORGANIZATION_TYPE = ResourceTypesFhirR4.Organization;
|
|
14
|
+
export const EXAMPLE_VERIFY_RESPONSE_JTI = 'urn:uuid:verify-resp-001';
|
|
15
|
+
export const EXAMPLE_VERIFY_RESPONSE_THID = 'verify-terms-001';
|
|
16
|
+
export const EXAMPLE_VERIFY_RESPONSE_BUNDLE_TYPE = 'application/bundle-api+json';
|
|
17
|
+
export const EXAMPLE_VERIFY_RESPONSE_DATE = '2026-03-12T21:12:26.646Z';
|
|
18
|
+
export const EXAMPLE_VERIFY_RESPONSE_PROOF_DATE = '2026-03-12T21:12:57.534Z';
|
|
19
|
+
export const EXAMPLE_VERIFY_RESPONSE_VERSION_ID = 'zPdfVersionHash001';
|
|
20
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_VC_ID = 'urn:uuid:org-vc-001';
|
|
21
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_VC_ID = 'urn:uuid:person-vc-001';
|
|
22
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_ENTRY_TYPE = 'Organization-verification-v1.0';
|
|
23
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ENTRY_TYPE = 'LegalRepresentative-verification-v1.0';
|
|
24
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT_ID = 'vc-jwt-1';
|
|
25
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT_ID = 'vc-jwt-2';
|
|
26
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT_FILENAME = 'Organization-verification-v1.0-1.jwt';
|
|
27
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT_FILENAME = 'LegalRepresentative-verification-v1.0-2.jwt';
|
|
28
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_JWT = '<vc-jwt-organization>';
|
|
29
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_JWT = '<vc-jwt-legal-representative>';
|
|
30
|
+
export const EXAMPLE_VERIFY_RESPONSE_MEDIA_TYPE = 'application/vc+jwt';
|
|
31
|
+
export const EXAMPLE_VERIFY_RESPONSE_ATTACHMENT_FORMAT = 'vc+jwt';
|
|
32
|
+
export const EXAMPLE_VERIFY_RESPONSE_STATUS_OK = '200';
|
|
33
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_KID = 'org-es384-001';
|
|
34
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_KID = 'controller-es384-001';
|
|
35
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_DID = 'did:web:globaldatacare.es:onehealth:organization:taxid:VATES-B00112233';
|
|
36
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_NAME = 'Alex Example';
|
|
37
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_GIVEN_NAME = 'Alex';
|
|
38
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_FAMILY_NAME = 'Example';
|
|
39
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_NATIONALITY = 'ES';
|
|
40
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ADDITIONAL_TYPE = 'ES384';
|
|
41
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ALTERNATE_NAME = EXAMPLE_VERIFY_RESPONSE_PERSON_KID;
|
|
42
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_ADDITIONAL_TYPE = 'sector=onehealth;section=dataprovider;kind=clinic;action=_index-provider,_research-provider';
|
|
43
|
+
export const EXAMPLE_VERIFY_RESPONSE_ADDRESS_TYPE = 'PostalAddress';
|
|
44
|
+
export const EXAMPLE_VERIFY_RESPONSE_ADDRESS_COUNTRY = 'ES';
|
|
45
|
+
export const EXAMPLE_VERIFY_RESPONSE_OCCUPATION_TYPE = 'Occupation';
|
|
46
|
+
export const EXAMPLE_VERIFY_RESPONSE_OCCUPATION_NAME = 'LegalRepresentative';
|
|
47
|
+
export const EXAMPLE_VERIFY_RESPONSE_OCCUPATION_IDENTIFIER = 'urn:ilo:ilostat:isco-08:1120';
|
|
48
|
+
export const EXAMPLE_VERIFY_RESPONSE_PROOF_TYPE = 'JsonWebSignature2020';
|
|
49
|
+
export const EXAMPLE_VERIFY_RESPONSE_PROOF_PURPOSE = 'assertionMethod';
|
|
50
|
+
export const EXAMPLE_VERIFY_RESPONSE_PROOF_VERIFICATION_METHOD = 'did:web:localhost%3A3310#verification-key-001';
|
|
51
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_PROOF_JWS = '<detached-jws-organization-truncated>';
|
|
52
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_PROOF_JWS = '<detached-jws-person-truncated>';
|
|
53
|
+
/**
|
|
54
|
+
* Shared success outcome reused at bundle level and item level.
|
|
55
|
+
*/
|
|
56
|
+
export const EXAMPLE_VERIFY_RESPONSE_SUCCESS_OUTCOME = {
|
|
57
|
+
resourceType: EXAMPLE_VERIFY_RESPONSE_OPERATION_OUTCOME_RESOURCE_TYPE,
|
|
58
|
+
issue: [
|
|
59
|
+
{
|
|
60
|
+
severity: IssueSeverity.Information,
|
|
61
|
+
code: IssueType.Informational,
|
|
62
|
+
diagnostics: 'Verification completed.',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_ITEM_OUTCOME = {
|
|
67
|
+
resourceType: EXAMPLE_VERIFY_RESPONSE_OPERATION_OUTCOME_RESOURCE_TYPE,
|
|
68
|
+
issue: [
|
|
69
|
+
{
|
|
70
|
+
severity: IssueSeverity.Information,
|
|
71
|
+
code: IssueType.Informational,
|
|
72
|
+
diagnostics: 'Organization credential extracted from verified document.',
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ITEM_OUTCOME = {
|
|
77
|
+
resourceType: EXAMPLE_VERIFY_RESPONSE_OPERATION_OUTCOME_RESOURCE_TYPE,
|
|
78
|
+
issue: [
|
|
79
|
+
{
|
|
80
|
+
severity: IssueSeverity.Information,
|
|
81
|
+
code: IssueType.Informational,
|
|
82
|
+
diagnostics: 'Legal representative credential extracted from verified document.',
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_PUBLIC_KEY_JWK = Object.freeze({
|
|
87
|
+
kty: 'EC',
|
|
88
|
+
crv: 'P-384',
|
|
89
|
+
x: 'org-pub-x',
|
|
90
|
+
y: 'org-pub-y',
|
|
91
|
+
alg: 'ES384',
|
|
92
|
+
kid: EXAMPLE_VERIFY_RESPONSE_ORG_KID,
|
|
93
|
+
});
|
|
94
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_PRIVATE_KEY_JWK = Object.freeze({
|
|
95
|
+
...EXAMPLE_VERIFY_RESPONSE_ORG_PUBLIC_KEY_JWK,
|
|
96
|
+
d: 'org-priv-d',
|
|
97
|
+
});
|
|
98
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_PUBLIC_KEY_JWK = Object.freeze({
|
|
99
|
+
kty: 'EC',
|
|
100
|
+
crv: 'P-384',
|
|
101
|
+
x: 'controller-x',
|
|
102
|
+
y: 'controller-y',
|
|
103
|
+
alg: 'ES384',
|
|
104
|
+
kid: EXAMPLE_VERIFY_RESPONSE_PERSON_KID,
|
|
105
|
+
});
|
|
106
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_AUTHORIZED_CATEGORY = DataspaceSectors.HealthCare;
|
|
107
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL = Object.freeze({
|
|
108
|
+
id: EXAMPLE_VERIFY_RESPONSE_ORG_VC_ID,
|
|
109
|
+
'@context': [W3cCredentialContexts.V2, EXAMPLE_VERIFY_RESPONSE_SCHEMA_ORG_CONTEXT],
|
|
110
|
+
type: [W3cCredentialTypes.VerifiableCredential, ActivationCredentialTypes.OrganizationCredential],
|
|
111
|
+
issuer: EXAMPLE_DEFAULT_ICA_DID,
|
|
112
|
+
validFrom: EXAMPLE_VERIFY_RESPONSE_DATE,
|
|
113
|
+
meta: {
|
|
114
|
+
versionId: EXAMPLE_VERIFY_RESPONSE_VERSION_ID,
|
|
115
|
+
},
|
|
116
|
+
credentialSubject: {
|
|
117
|
+
id: EXAMPLE_VERIFY_RESPONSE_ORG_DID,
|
|
118
|
+
'@type': EXAMPLE_VERIFY_RESPONSE_ORGANIZATION_TYPE,
|
|
119
|
+
legalName: EXAMPLE_PROVIDER_LEGAL_NAME,
|
|
120
|
+
taxID: EXAMPLE_PROVIDER_TAX_ID,
|
|
121
|
+
sameAs: EXAMPLE_TENANT_SERVICE_DID,
|
|
122
|
+
url: EXAMPLE_PROVIDER_DOMAIN,
|
|
123
|
+
alternateName: 'example-provider',
|
|
124
|
+
additionalType: EXAMPLE_VERIFY_RESPONSE_ORG_ADDITIONAL_TYPE,
|
|
125
|
+
makesOffer: {
|
|
126
|
+
'@type': 'Offer',
|
|
127
|
+
category: EXAMPLE_VERIFY_RESPONSE_ORG_AUTHORIZED_CATEGORY,
|
|
128
|
+
},
|
|
129
|
+
address: {
|
|
130
|
+
'@type': EXAMPLE_VERIFY_RESPONSE_ADDRESS_TYPE,
|
|
131
|
+
addressCountry: EXAMPLE_VERIFY_RESPONSE_ADDRESS_COUNTRY,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
evidence: [],
|
|
135
|
+
proof: {
|
|
136
|
+
type: EXAMPLE_VERIFY_RESPONSE_PROOF_TYPE,
|
|
137
|
+
created: EXAMPLE_VERIFY_RESPONSE_PROOF_DATE,
|
|
138
|
+
proofPurpose: EXAMPLE_VERIFY_RESPONSE_PROOF_PURPOSE,
|
|
139
|
+
verificationMethod: EXAMPLE_VERIFY_RESPONSE_PROOF_VERIFICATION_METHOD,
|
|
140
|
+
jws: EXAMPLE_VERIFY_RESPONSE_ORG_PROOF_JWS,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_CREDENTIAL = Object.freeze({
|
|
144
|
+
id: EXAMPLE_VERIFY_RESPONSE_PERSON_VC_ID,
|
|
145
|
+
'@context': [W3cCredentialContexts.V2, EXAMPLE_VERIFY_RESPONSE_SCHEMA_ORG_CONTEXT],
|
|
146
|
+
type: [
|
|
147
|
+
W3cCredentialTypes.VerifiableCredential,
|
|
148
|
+
ActivationCredentialTypes.PersonCredential,
|
|
149
|
+
ActivationCredentialTypes.LegalRepresentativeCredential,
|
|
150
|
+
],
|
|
151
|
+
issuer: EXAMPLE_DEFAULT_ICA_DID,
|
|
152
|
+
validFrom: EXAMPLE_VERIFY_RESPONSE_DATE,
|
|
153
|
+
meta: {
|
|
154
|
+
versionId: EXAMPLE_VERIFY_RESPONSE_VERSION_ID,
|
|
155
|
+
},
|
|
156
|
+
credentialSubject: {
|
|
157
|
+
id: EXAMPLE_REPRESENTATIVE_SUBJECT_URN,
|
|
158
|
+
'@type': EXAMPLE_VERIFY_RESPONSE_PERSON_TYPE,
|
|
159
|
+
name: EXAMPLE_VERIFY_RESPONSE_PERSON_NAME,
|
|
160
|
+
givenName: EXAMPLE_VERIFY_RESPONSE_PERSON_GIVEN_NAME,
|
|
161
|
+
familyName: EXAMPLE_VERIFY_RESPONSE_PERSON_FAMILY_NAME,
|
|
162
|
+
identifier: EXAMPLE_REPRESENTATIVE_IDENTIFIER,
|
|
163
|
+
nationality: EXAMPLE_VERIFY_RESPONSE_PERSON_NATIONALITY,
|
|
164
|
+
sameAs: EXAMPLE_REPRESENTATIVE_SAME_AS,
|
|
165
|
+
hasCredential: {
|
|
166
|
+
material: EXAMPLE_ORG_CONTROLLER_SIGNING_KEY_ID,
|
|
167
|
+
},
|
|
168
|
+
hasOccupation: {
|
|
169
|
+
'@type': EXAMPLE_VERIFY_RESPONSE_OCCUPATION_TYPE,
|
|
170
|
+
name: EXAMPLE_VERIFY_RESPONSE_OCCUPATION_NAME,
|
|
171
|
+
identifier: EXAMPLE_VERIFY_RESPONSE_OCCUPATION_IDENTIFIER,
|
|
172
|
+
},
|
|
173
|
+
memberOf: {
|
|
174
|
+
'@type': EXAMPLE_VERIFY_RESPONSE_ORGANIZATION_TYPE,
|
|
175
|
+
legalName: EXAMPLE_PROVIDER_LEGAL_NAME,
|
|
176
|
+
taxID: EXAMPLE_PROVIDER_TAX_ID,
|
|
177
|
+
},
|
|
178
|
+
alternateName: EXAMPLE_VERIFY_RESPONSE_PERSON_ALTERNATE_NAME,
|
|
179
|
+
additionalType: EXAMPLE_VERIFY_RESPONSE_PERSON_ADDITIONAL_TYPE,
|
|
180
|
+
},
|
|
181
|
+
evidence: [],
|
|
182
|
+
proof: {
|
|
183
|
+
type: EXAMPLE_VERIFY_RESPONSE_PROOF_TYPE,
|
|
184
|
+
created: EXAMPLE_VERIFY_RESPONSE_PROOF_DATE,
|
|
185
|
+
proofPurpose: EXAMPLE_VERIFY_RESPONSE_PROOF_PURPOSE,
|
|
186
|
+
verificationMethod: EXAMPLE_VERIFY_RESPONSE_PROOF_VERIFICATION_METHOD,
|
|
187
|
+
jws: EXAMPLE_VERIFY_RESPONSE_PERSON_PROOF_JWS,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT = Object.freeze({
|
|
191
|
+
id: EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT_ID,
|
|
192
|
+
format: EXAMPLE_VERIFY_RESPONSE_ATTACHMENT_FORMAT,
|
|
193
|
+
media_type: EXAMPLE_VERIFY_RESPONSE_MEDIA_TYPE,
|
|
194
|
+
filename: EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT_FILENAME,
|
|
195
|
+
data: {
|
|
196
|
+
json: {
|
|
197
|
+
format: EXAMPLE_VERIFY_RESPONSE_ATTACHMENT_FORMAT,
|
|
198
|
+
jwt: EXAMPLE_VERIFY_RESPONSE_ORG_JWT,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
export const EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT = Object.freeze({
|
|
203
|
+
id: EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT_ID,
|
|
204
|
+
format: EXAMPLE_VERIFY_RESPONSE_ATTACHMENT_FORMAT,
|
|
205
|
+
media_type: EXAMPLE_VERIFY_RESPONSE_MEDIA_TYPE,
|
|
206
|
+
filename: EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT_FILENAME,
|
|
207
|
+
data: {
|
|
208
|
+
json: {
|
|
209
|
+
format: EXAMPLE_VERIFY_RESPONSE_ATTACHMENT_FORMAT,
|
|
210
|
+
jwt: EXAMPLE_VERIFY_RESPONSE_PERSON_JWT,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
/**
|
|
215
|
+
* Canonical `_verify-response` success example shared across ICA repos.
|
|
216
|
+
*/
|
|
217
|
+
export const EXAMPLE_ICA_VERIFY_TERMS_RESPONSE_SUCCESS = {
|
|
218
|
+
jti: EXAMPLE_VERIFY_RESPONSE_JTI,
|
|
219
|
+
iss: EXAMPLE_DEFAULT_ICA_DID,
|
|
220
|
+
aud: EXAMPLE_DEFAULT_ICA_DID,
|
|
221
|
+
thid: EXAMPLE_VERIFY_RESPONSE_THID,
|
|
222
|
+
type: EXAMPLE_VERIFY_RESPONSE_BUNDLE_TYPE,
|
|
223
|
+
attachments: [
|
|
224
|
+
EXAMPLE_VERIFY_RESPONSE_ORG_ATTACHMENT,
|
|
225
|
+
EXAMPLE_VERIFY_RESPONSE_PERSON_ATTACHMENT,
|
|
226
|
+
],
|
|
227
|
+
body: {
|
|
228
|
+
resourceType: EXAMPLE_BUNDLE_RESOURCE_TYPE,
|
|
229
|
+
type: EXAMPLE_VERIFY_RESPONSE_BATCH_RESPONSE_TYPE,
|
|
230
|
+
total: 2,
|
|
231
|
+
issues: EXAMPLE_VERIFY_RESPONSE_SUCCESS_OUTCOME,
|
|
232
|
+
data: [
|
|
233
|
+
{
|
|
234
|
+
type: EXAMPLE_VERIFY_RESPONSE_ORG_ENTRY_TYPE,
|
|
235
|
+
publicKeyJwk: EXAMPLE_VERIFY_RESPONSE_ORG_PUBLIC_KEY_JWK,
|
|
236
|
+
privateKeyJwk: EXAMPLE_VERIFY_RESPONSE_ORG_PRIVATE_KEY_JWK,
|
|
237
|
+
keySource: 'generated',
|
|
238
|
+
response: {
|
|
239
|
+
status: EXAMPLE_VERIFY_RESPONSE_STATUS_OK,
|
|
240
|
+
outcome: EXAMPLE_VERIFY_RESPONSE_ORG_ITEM_OUTCOME,
|
|
241
|
+
},
|
|
242
|
+
resource: EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: EXAMPLE_VERIFY_RESPONSE_PERSON_ENTRY_TYPE,
|
|
246
|
+
publicKeyJwk: EXAMPLE_VERIFY_RESPONSE_PERSON_PUBLIC_KEY_JWK,
|
|
247
|
+
response: {
|
|
248
|
+
status: EXAMPLE_VERIFY_RESPONSE_STATUS_OK,
|
|
249
|
+
outcome: EXAMPLE_VERIFY_RESPONSE_PERSON_ITEM_OUTCOME,
|
|
250
|
+
},
|
|
251
|
+
resource: EXAMPLE_VERIFY_RESPONSE_PERSON_CREDENTIAL,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Returns a detached deep clone of the canonical ICA `_verify-response`
|
|
258
|
+
* success example so tests/docs can tweak fields without mutating the shared
|
|
259
|
+
* frozen baseline.
|
|
260
|
+
*/
|
|
261
|
+
export function cloneIcaVerifyTermsResponseSuccessExample() {
|
|
262
|
+
return JSON.parse(JSON.stringify(EXAMPLE_ICA_VERIFY_TERMS_RESPONSE_SUCCESS));
|
|
263
|
+
}
|
package/dist/examples/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from './shared';
|
|
2
2
|
export * from './ica-activation-proof';
|
|
3
|
+
export * from './ica-verify-response';
|
|
3
4
|
export * from './dataspace-discovery';
|
|
4
5
|
export * from './organization-controller';
|
|
6
|
+
export * from './organization-did-binding';
|
|
7
|
+
export * from './legal-organization-verification-transaction';
|
|
5
8
|
export * from './individual-controller';
|
|
6
9
|
export * from './professional';
|
|
7
10
|
export * from './employee';
|
package/dist/examples/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from './shared.js';
|
|
2
2
|
export * from './ica-activation-proof.js';
|
|
3
|
+
export * from './ica-verify-response.js';
|
|
3
4
|
export * from './dataspace-discovery.js';
|
|
4
5
|
export * from './organization-controller.js';
|
|
6
|
+
export * from './organization-did-binding.js';
|
|
7
|
+
export * from './legal-organization-verification-transaction.js';
|
|
5
8
|
export * from './individual-controller.js';
|
|
6
9
|
export * from './professional.js';
|
|
7
10
|
export * from './employee.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const EXAMPLE_LEGAL_ORGANIZATION_VERIFICATION_TRANSACTION_BUNDLE: import("..").BundleJsonApi<import("..").ErrorEntry | import("..").BundleEntry>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { ClaimsOrganizationSchemaorg, ClaimsPersonSchemaorg, ClaimsServiceSchemaorg, } from '../constants/schemaorg.js';
|
|
3
|
+
import { buildLegalOrganizationVerificationTransactionBundle, } from '../utils/legal-organization-verification-transaction.js';
|
|
4
|
+
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
|
+
* Canonical host-onboarding transaction example for the new ICA verification
|
|
7
|
+
* first step.
|
|
8
|
+
*
|
|
9
|
+
* Why this exists:
|
|
10
|
+
* - BFF/portal integrations need one stable example of the GW CORE request
|
|
11
|
+
* that wraps an ICA `_verify`
|
|
12
|
+
* - the example keeps the controller business binding separate from any
|
|
13
|
+
* technical DIDComm communication key
|
|
14
|
+
*/
|
|
15
|
+
const exampleControllerBinding = {
|
|
16
|
+
did: EXAMPLE_CONTROLLER_BINDING.did,
|
|
17
|
+
sameAs: EXAMPLE_CONTROLLER_BINDING.sameAs,
|
|
18
|
+
publicKeyJwk: { ...EXAMPLE_CONTROLLER_BINDING.publicKeyJwk },
|
|
19
|
+
...(EXAMPLE_CONTROLLER_BINDING.jwks
|
|
20
|
+
? {
|
|
21
|
+
jwks: {
|
|
22
|
+
keys: EXAMPLE_CONTROLLER_BINDING.jwks.keys.map((item) => ({ ...item })),
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
: {}),
|
|
26
|
+
};
|
|
27
|
+
export const EXAMPLE_LEGAL_ORGANIZATION_VERIFICATION_TRANSACTION_BUNDLE = buildLegalOrganizationVerificationTransactionBundle({
|
|
28
|
+
claims: {
|
|
29
|
+
'@context': 'org.schema',
|
|
30
|
+
[ClaimsOrganizationSchemaorg.legalName]: EXAMPLE_ORGANIZATION_LEGAL_NAME,
|
|
31
|
+
[ClaimsOrganizationSchemaorg.identifierType]: 'taxID',
|
|
32
|
+
[ClaimsOrganizationSchemaorg.identifierValue]: EXAMPLE_LEGAL_ORGANIZATION_TAX_ID,
|
|
33
|
+
[ClaimsOrganizationSchemaorg.taxId]: EXAMPLE_LEGAL_ORGANIZATION_TAX_ID,
|
|
34
|
+
[ClaimsOrganizationSchemaorg.addressCountry]: EXAMPLE_JURISDICTION,
|
|
35
|
+
[ClaimsPersonSchemaorg.email]: EXAMPLE_EMAIL_CONTROLLER_ORG,
|
|
36
|
+
[ClaimsServiceSchemaorg.category]: EXAMPLE_SECTOR,
|
|
37
|
+
[ClaimsServiceSchemaorg.identifier]: EXAMPLE_TENANT_SERVICE_DID,
|
|
38
|
+
[ClaimsServiceSchemaorg.url]: `https://operator.example.net/acme/cds-${String(EXAMPLE_JURISDICTION).toLowerCase()}/v1/${EXAMPLE_SECTOR}`,
|
|
39
|
+
},
|
|
40
|
+
controller: exampleControllerBinding,
|
|
41
|
+
organization: {
|
|
42
|
+
did: EXAMPLE_TENANT_SERVICE_DID,
|
|
43
|
+
publicKeyJwk: {
|
|
44
|
+
kid: 'organization-signing-es384-001',
|
|
45
|
+
kty: 'EC',
|
|
46
|
+
crv: 'P-384',
|
|
47
|
+
x: '<organization-sign-x>',
|
|
48
|
+
y: '<organization-sign-y>',
|
|
49
|
+
alg: 'ES384',
|
|
50
|
+
use: 'sig',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
legalRepresentativePayload: {
|
|
54
|
+
email: EXAMPLE_EMAIL_CONTROLLER_ORG,
|
|
55
|
+
},
|
|
56
|
+
verification: {
|
|
57
|
+
resourceType: 'contract',
|
|
58
|
+
},
|
|
59
|
+
attachments: [{
|
|
60
|
+
id: 'signed-terms-pdf-001',
|
|
61
|
+
media_type: 'application/pdf',
|
|
62
|
+
data: {
|
|
63
|
+
links: [EXAMPLE_SIGNED_TERMS_PDF_URL],
|
|
64
|
+
},
|
|
65
|
+
}],
|
|
66
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const EXAMPLE_ORGANIZATION_DID_BINDING_BUNDLE: import("..").BundleJsonApi<import("..").ErrorEntry | import("..").BundleEntry>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { buildOrganizationDidBindingBundle } from '../utils/organization-did-binding.js';
|
|
3
|
+
import { EXAMPLE_CONTROLLER_BINDING, EXAMPLE_TENANT_SERVICE_DID, } from './shared.js';
|
|
4
|
+
export const EXAMPLE_ORGANIZATION_DID_BINDING_BUNDLE = buildOrganizationDidBindingBundle({
|
|
5
|
+
organization: {
|
|
6
|
+
url: [
|
|
7
|
+
'https://provider.example.org',
|
|
8
|
+
EXAMPLE_TENANT_SERVICE_DID,
|
|
9
|
+
],
|
|
10
|
+
},
|
|
11
|
+
controller: {
|
|
12
|
+
sameAs: EXAMPLE_CONTROLLER_BINDING.sameAs,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
@@ -17,6 +17,8 @@ export declare const EXAMPLE_NETWORK_TYPE: "test";
|
|
|
17
17
|
export declare const EXAMPLE_ROUTE_VERSION: "v1";
|
|
18
18
|
export declare const EXAMPLE_SECTOR: "health-care";
|
|
19
19
|
export declare const EXAMPLE_EMAIL_CONTROLLER_ORG: "controller@acme.org";
|
|
20
|
+
export declare const EXAMPLE_ORGANIZATION_LEGAL_NAME: "ACME HEALTH SL";
|
|
21
|
+
export declare const EXAMPLE_LEGAL_ORGANIZATION_TAX_ID: "VATES-B00112233";
|
|
20
22
|
export declare const EXAMPLE_EMAIL_CONTROLLER_INDIVIDUAL: "ana.parent@example.org";
|
|
21
23
|
export declare const EXAMPLE_INTEROPERABLE_CONTEXT_FHIR_API: "org.hl7.fhir.api";
|
|
22
24
|
export declare const EXAMPLE_SELF_REGISTERED_INDIVIDUAL_ALTERNATE_NAME: "Jane";
|
|
@@ -27,6 +29,7 @@ export declare const EXAMPLE_SELF_REGISTERED_INDIVIDUAL_BIRTH_YEAR: "1980";
|
|
|
27
29
|
export declare const EXAMPLE_REGISTERED_SUBJECT_ALTERNATE_NAME: "Doraemon";
|
|
28
30
|
export declare const EXAMPLE_REGISTERED_SUBJECT_BIRTH_YEAR: "2020";
|
|
29
31
|
export declare const EXAMPLE_PDF_CONSENT_DATE: "2026-06-08";
|
|
32
|
+
export declare const EXAMPLE_SIGNED_TERMS_PDF_URL: "https://portal.example.org/files/legal-organization-signed-terms.pdf";
|
|
30
33
|
/**
|
|
31
34
|
* Public provider domain selected during autodiscovery.
|
|
32
35
|
*
|
package/dist/examples/shared.js
CHANGED
|
@@ -32,6 +32,8 @@ export const EXAMPLE_NETWORK_TYPE = HostNetworkTypes.Test;
|
|
|
32
32
|
export const EXAMPLE_ROUTE_VERSION = 'v1';
|
|
33
33
|
export const EXAMPLE_SECTOR = DataspaceSectors.HealthCare;
|
|
34
34
|
export const EXAMPLE_EMAIL_CONTROLLER_ORG = 'controller@acme.org';
|
|
35
|
+
export const EXAMPLE_ORGANIZATION_LEGAL_NAME = 'ACME HEALTH SL';
|
|
36
|
+
export const EXAMPLE_LEGAL_ORGANIZATION_TAX_ID = 'VATES-B00112233';
|
|
35
37
|
export const EXAMPLE_EMAIL_CONTROLLER_INDIVIDUAL = 'ana.parent@example.org';
|
|
36
38
|
export const EXAMPLE_INTEROPERABLE_CONTEXT_FHIR_API = Format.FHIR_API;
|
|
37
39
|
export const EXAMPLE_SELF_REGISTERED_INDIVIDUAL_ALTERNATE_NAME = 'Jane';
|
|
@@ -42,6 +44,7 @@ export const EXAMPLE_SELF_REGISTERED_INDIVIDUAL_BIRTH_YEAR = '1980';
|
|
|
42
44
|
export const EXAMPLE_REGISTERED_SUBJECT_ALTERNATE_NAME = 'Doraemon';
|
|
43
45
|
export const EXAMPLE_REGISTERED_SUBJECT_BIRTH_YEAR = '2020';
|
|
44
46
|
export const EXAMPLE_PDF_CONSENT_DATE = '2026-06-08';
|
|
47
|
+
export const EXAMPLE_SIGNED_TERMS_PDF_URL = 'https://portal.example.org/files/legal-organization-signed-terms.pdf';
|
|
45
48
|
/**
|
|
46
49
|
* Public provider domain selected during autodiscovery.
|
|
47
50
|
*
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export * from './family-registration-test-data';
|
|
|
49
49
|
export * from './individual-form-pdf';
|
|
50
50
|
export * from './individual-organization-claims';
|
|
51
51
|
export * from './organization-lifecycle';
|
|
52
|
+
export * from './organization-did-binding';
|
|
52
53
|
export * from './individual-organization-lifecycle';
|
|
53
54
|
export * from './individual-onboarding-editor';
|
|
54
55
|
export * from './individual-onboarding-document-reference';
|
|
@@ -60,6 +61,7 @@ export * from './interoperable-resource-operation';
|
|
|
60
61
|
export * from './jwt';
|
|
61
62
|
export * from './jwk-thumbprint';
|
|
62
63
|
export * from './legal-organization-onboarding';
|
|
64
|
+
export * from './legal-organization-verification-transaction';
|
|
63
65
|
export * from './license';
|
|
64
66
|
export * from './license-commercial-search';
|
|
65
67
|
export * from './license-list-search';
|
package/dist/utils/index.js
CHANGED
|
@@ -49,6 +49,7 @@ export * from './family-registration-test-data.js';
|
|
|
49
49
|
export * from './individual-form-pdf.js';
|
|
50
50
|
export * from './individual-organization-claims.js';
|
|
51
51
|
export * from './organization-lifecycle.js';
|
|
52
|
+
export * from './organization-did-binding.js';
|
|
52
53
|
export * from './individual-organization-lifecycle.js';
|
|
53
54
|
export * from './individual-onboarding-editor.js';
|
|
54
55
|
export * from './individual-onboarding-document-reference.js';
|
|
@@ -60,6 +61,7 @@ export * from './interoperable-resource-operation.js';
|
|
|
60
61
|
export * from './jwt.js';
|
|
61
62
|
export * from './jwk-thumbprint.js';
|
|
62
63
|
export * from './legal-organization-onboarding.js';
|
|
64
|
+
export * from './legal-organization-verification-transaction.js';
|
|
63
65
|
export * from './license.js';
|
|
64
66
|
export * from './license-commercial-search.js';
|
|
65
67
|
export * from './license-list-search.js';
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
/**
|
|
79
|
+
* Builds the canonical Bundle payload for host-side legal organization
|
|
80
|
+
* verification transactions.
|
|
81
|
+
*
|
|
82
|
+
* Contract notes:
|
|
83
|
+
* - business claims remain in `meta.claims`
|
|
84
|
+
* - controller binding material remains in `resource.controller.*`
|
|
85
|
+
* - organization signing material remains in `resource.organization.*`
|
|
86
|
+
* - PDF evidence or URL attachments stay at the DIDComm-message level
|
|
87
|
+
* - `Service.category` is the canonical business-sector input later used by GW
|
|
88
|
+
* to target the appropriate ICA verification route
|
|
89
|
+
*/
|
|
90
|
+
export declare function buildLegalOrganizationVerificationTransactionBundle(input: LegalOrganizationVerificationTransactionInput): BundleJsonApi;
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
/**
|
|
25
|
+
* Builds the canonical Bundle payload for host-side legal organization
|
|
26
|
+
* verification transactions.
|
|
27
|
+
*
|
|
28
|
+
* Contract notes:
|
|
29
|
+
* - business claims remain in `meta.claims`
|
|
30
|
+
* - controller binding material remains in `resource.controller.*`
|
|
31
|
+
* - organization signing material remains in `resource.organization.*`
|
|
32
|
+
* - PDF evidence or URL attachments stay at the DIDComm-message level
|
|
33
|
+
* - `Service.category` is the canonical business-sector input later used by GW
|
|
34
|
+
* to target the appropriate ICA verification route
|
|
35
|
+
*/
|
|
36
|
+
export function buildLegalOrganizationVerificationTransactionBundle(input) {
|
|
37
|
+
const businessSector = normalizeText(input.claims?.[ClaimsServiceSchemaorg.category]);
|
|
38
|
+
if (!businessSector) {
|
|
39
|
+
throw new Error(`buildLegalOrganizationVerificationTransactionBundle requires ${ClaimsServiceSchemaorg.category}.`);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
resourceType: 'Bundle',
|
|
43
|
+
type: 'collection',
|
|
44
|
+
total: 1,
|
|
45
|
+
data: [{
|
|
46
|
+
type: LegalOrganizationVerificationTransactionEntryTypes.Request,
|
|
47
|
+
meta: {
|
|
48
|
+
claims: input.claims,
|
|
49
|
+
},
|
|
50
|
+
resource: {
|
|
51
|
+
controller: input.controller,
|
|
52
|
+
...(input.organization ? { organization: input.organization } : {}),
|
|
53
|
+
...(input.legalRepresentativePayload
|
|
54
|
+
? { legalRepresentativePayload: input.legalRepresentativePayload }
|
|
55
|
+
: {}),
|
|
56
|
+
verification: {
|
|
57
|
+
resourceType: normalizeText(input.verification?.resourceType) || 'contract',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
}],
|
|
61
|
+
...(Array.isArray(input.attachments) && input.attachments.length > 0
|
|
62
|
+
? { attachments: input.attachments }
|
|
63
|
+
: {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -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
|
+
}
|