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 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
+ }
@@ -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';
@@ -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
  *
@@ -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
  *
@@ -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';
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-common-utils-ts",
3
- "version": "2.0.1",
3
+ "version": "2.0.4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },