gdc-common-utils-ts 2.0.2 → 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 +5 -0
- package/dist/examples/ica-verify-response.js +6 -0
- package/dist/examples/index.d.ts +2 -0
- package/dist/examples/index.js +2 -0
- package/dist/examples/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.
|
|
@@ -136,6 +136,7 @@ export declare const EXAMPLE_VERIFY_RESPONSE_PERSON_PUBLIC_KEY_JWK: Readonly<{
|
|
|
136
136
|
alg: "ES384";
|
|
137
137
|
kid: "controller-es384-001";
|
|
138
138
|
}>;
|
|
139
|
+
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_AUTHORIZED_CATEGORY: "health-care";
|
|
139
140
|
export declare const EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL: Readonly<{
|
|
140
141
|
id: "urn:uuid:org-vc-001";
|
|
141
142
|
'@context': ("https://www.w3.org/ns/credentials/v2" | "https://schema.org")[];
|
|
@@ -154,6 +155,10 @@ export declare const EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL: Readonly<{
|
|
|
154
155
|
url: "health-care.provider.example.org";
|
|
155
156
|
alternateName: string;
|
|
156
157
|
additionalType: "sector=onehealth;section=dataprovider;kind=clinic;action=_index-provider,_research-provider";
|
|
158
|
+
makesOffer: {
|
|
159
|
+
'@type': string;
|
|
160
|
+
category: "health-care";
|
|
161
|
+
};
|
|
157
162
|
address: {
|
|
158
163
|
'@type': "PostalAddress";
|
|
159
164
|
addressCountry: "ES";
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Always create JSDoc, do not use strings inline in keys nor values, use types instead, and reuse the data test examples.
|
|
3
3
|
import { ActivationCredentialTypes, W3cCredentialContexts, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
|
|
4
4
|
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
5
|
+
import { DataspaceSectors } from '../constants/sectors.js';
|
|
5
6
|
import { IssueSeverity, IssueType } from '../models/issue.js';
|
|
6
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';
|
|
7
8
|
import { EXAMPLE_ORG_CONTROLLER_SIGNING_KEY_ID, EXAMPLE_REPRESENTATIVE_IDENTIFIER, EXAMPLE_REPRESENTATIVE_SAME_AS, EXAMPLE_REPRESENTATIVE_SUBJECT_URN, } from './ica-activation-proof.js';
|
|
@@ -102,6 +103,7 @@ export const EXAMPLE_VERIFY_RESPONSE_PERSON_PUBLIC_KEY_JWK = Object.freeze({
|
|
|
102
103
|
alg: 'ES384',
|
|
103
104
|
kid: EXAMPLE_VERIFY_RESPONSE_PERSON_KID,
|
|
104
105
|
});
|
|
106
|
+
export const EXAMPLE_VERIFY_RESPONSE_ORG_AUTHORIZED_CATEGORY = DataspaceSectors.HealthCare;
|
|
105
107
|
export const EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL = Object.freeze({
|
|
106
108
|
id: EXAMPLE_VERIFY_RESPONSE_ORG_VC_ID,
|
|
107
109
|
'@context': [W3cCredentialContexts.V2, EXAMPLE_VERIFY_RESPONSE_SCHEMA_ORG_CONTEXT],
|
|
@@ -120,6 +122,10 @@ export const EXAMPLE_VERIFY_RESPONSE_ORG_CREDENTIAL = Object.freeze({
|
|
|
120
122
|
url: EXAMPLE_PROVIDER_DOMAIN,
|
|
121
123
|
alternateName: 'example-provider',
|
|
122
124
|
additionalType: EXAMPLE_VERIFY_RESPONSE_ORG_ADDITIONAL_TYPE,
|
|
125
|
+
makesOffer: {
|
|
126
|
+
'@type': 'Offer',
|
|
127
|
+
category: EXAMPLE_VERIFY_RESPONSE_ORG_AUTHORIZED_CATEGORY,
|
|
128
|
+
},
|
|
123
129
|
address: {
|
|
124
130
|
'@type': EXAMPLE_VERIFY_RESPONSE_ADDRESS_TYPE,
|
|
125
131
|
addressCountry: EXAMPLE_VERIFY_RESPONSE_ADDRESS_COUNTRY,
|
package/dist/examples/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export * from './ica-activation-proof';
|
|
|
3
3
|
export * from './ica-verify-response';
|
|
4
4
|
export * from './dataspace-discovery';
|
|
5
5
|
export * from './organization-controller';
|
|
6
|
+
export * from './organization-did-binding';
|
|
7
|
+
export * from './legal-organization-verification-transaction';
|
|
6
8
|
export * from './individual-controller';
|
|
7
9
|
export * from './professional';
|
|
8
10
|
export * from './employee';
|
package/dist/examples/index.js
CHANGED
|
@@ -3,6 +3,8 @@ export * from './ica-activation-proof.js';
|
|
|
3
3
|
export * from './ica-verify-response.js';
|
|
4
4
|
export * from './dataspace-discovery.js';
|
|
5
5
|
export * from './organization-controller.js';
|
|
6
|
+
export * from './organization-did-binding.js';
|
|
7
|
+
export * from './legal-organization-verification-transaction.js';
|
|
6
8
|
export * from './individual-controller.js';
|
|
7
9
|
export * from './professional.js';
|
|
8
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
|
+
}
|