gdc-common-utils-ts 2.4.1 → 2.5.1
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 +15 -6
- package/dist/constants/healthcare.d.ts +13 -12
- package/dist/constants/healthcare.js +25 -25
- package/dist/constants/schemaorg.d.ts +2 -0
- package/dist/constants/schemaorg.js +2 -0
- package/dist/constants/verifiable-credentials.d.ts +8 -0
- package/dist/constants/verifiable-credentials.js +10 -0
- package/dist/examples/employee.d.ts +1 -1
- package/dist/examples/employee.js +2 -2
- package/dist/examples/ica-activation-proof.d.ts +1 -3
- package/dist/examples/ica-activation-proof.js +1 -3
- package/dist/examples/ica-verify-response.d.ts +2 -2
- package/dist/examples/ica-verify-response.js +1 -1
- package/dist/models/device-license.d.ts +2 -2
- package/dist/models/did.d.ts +2 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/subject-identifier-ledger.d.ts +13 -2
- package/dist/models/subject-identity.d.ts +36 -0
- package/dist/models/subject-identity.js +1 -0
- package/dist/utils/activation-policy.d.ts +2 -5
- package/dist/utils/activation-policy.js +4 -12
- package/dist/utils/actor-identifier.d.ts +9 -13
- package/dist/utils/actor-identifier.js +20 -21
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/jwk-thumbprint.d.ts +8 -0
- package/dist/utils/jwk-thumbprint.js +11 -0
- package/dist/utils/legal-organization-onboarding-editor.d.ts +2 -0
- package/dist/utils/legal-organization-onboarding-editor.js +1 -3
- package/dist/utils/legal-organization-verification-result.d.ts +45 -0
- package/dist/utils/legal-organization-verification-result.js +78 -0
- package/dist/utils/legal-organization-verification-transaction.d.ts +13 -0
- package/dist/utils/legal-organization-verification-transaction.js +6 -0
- package/dist/utils/organization-registration-authorization.d.ts +65 -0
- package/dist/utils/organization-registration-authorization.js +112 -0
- package/dist/utils/subject-identity.d.ts +30 -0
- package/dist/utils/subject-identity.js +127 -0
- package/dist/utils/vp-token.d.ts +14 -0
- package/dist/utils/vp-token.js +19 -1
- package/package.json +1 -1
package/dist/utils/index.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ export * from './jwt-signer';
|
|
|
83
83
|
export * from './jwk-thumbprint';
|
|
84
84
|
export * from './legal-organization-onboarding';
|
|
85
85
|
export * from './legal-organization-verification-transaction';
|
|
86
|
+
export * from './organization-registration-authorization';
|
|
86
87
|
export * from './local-terminology-provider';
|
|
87
88
|
export * from './license';
|
|
88
89
|
export * from './license-commercial-search';
|
|
@@ -102,6 +103,7 @@ export * from './permission-templates';
|
|
|
102
103
|
export * from './smart-scope';
|
|
103
104
|
export * from './service-act-reasons';
|
|
104
105
|
export * from './same-as';
|
|
106
|
+
export * from './subject-identity';
|
|
105
107
|
export * from './subject-identity-binding';
|
|
106
108
|
export * from './activation-request';
|
|
107
109
|
export * from './actor-identifier';
|
package/dist/utils/index.js
CHANGED
|
@@ -83,6 +83,7 @@ export * from './jwt-signer.js';
|
|
|
83
83
|
export * from './jwk-thumbprint.js';
|
|
84
84
|
export * from './legal-organization-onboarding.js';
|
|
85
85
|
export * from './legal-organization-verification-transaction.js';
|
|
86
|
+
export * from './organization-registration-authorization.js';
|
|
86
87
|
export * from './local-terminology-provider.js';
|
|
87
88
|
export * from './license.js';
|
|
88
89
|
export * from './license-commercial-search.js';
|
|
@@ -102,6 +103,7 @@ export * from './permission-templates.js';
|
|
|
102
103
|
export * from './smart-scope.js';
|
|
103
104
|
export * from './service-act-reasons.js';
|
|
104
105
|
export * from './same-as.js';
|
|
106
|
+
export * from './subject-identity.js';
|
|
105
107
|
export * from './subject-identity-binding.js';
|
|
106
108
|
export * from './activation-request.js';
|
|
107
109
|
export * from './actor-identifier.js';
|
|
@@ -38,3 +38,11 @@ export declare function computeRfc7638JwkThumbprint(jwk: ThumbprintableJwk): str
|
|
|
38
38
|
* `urn:ietf:params:oauth:jwk-thumbprint:sha-256:<base64url>`
|
|
39
39
|
*/
|
|
40
40
|
export declare function toJwkThumbprintSha256Urn(jwk: ThumbprintableJwk): string;
|
|
41
|
+
/**
|
|
42
|
+
* Returns a public JWK whose `kid` is derived exclusively from its public key
|
|
43
|
+
* material. Caller-provided aliases are deliberately replaced so DID methods,
|
|
44
|
+
* credentials and confidential-storage indexes share one RFC 9278 identifier.
|
|
45
|
+
*/
|
|
46
|
+
export declare function withJwkThumbprintSha256Kid<T extends ThumbprintableJwk>(jwk: T): T & {
|
|
47
|
+
kid: string;
|
|
48
|
+
};
|
|
@@ -55,3 +55,14 @@ export function computeRfc7638JwkThumbprint(jwk) {
|
|
|
55
55
|
export function toJwkThumbprintSha256Urn(jwk) {
|
|
56
56
|
return `${UrnPrefixes.JwkThumbprintSha256KeyId}${computeRfc7638JwkThumbprint(jwk)}`;
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns a public JWK whose `kid` is derived exclusively from its public key
|
|
60
|
+
* material. Caller-provided aliases are deliberately replaced so DID methods,
|
|
61
|
+
* credentials and confidential-storage indexes share one RFC 9278 identifier.
|
|
62
|
+
*/
|
|
63
|
+
export function withJwkThumbprintSha256Kid(jwk) {
|
|
64
|
+
return {
|
|
65
|
+
...jwk,
|
|
66
|
+
kid: toJwkThumbprintSha256Urn(jwk),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -106,6 +106,7 @@ export interface LegalOrganizationOnboardingFacade {
|
|
|
106
106
|
buildVerificationTransactionInput(fields: LegalOrganizationFormTemplateFields, input: Readonly<{
|
|
107
107
|
controller: LegalOrganizationVerificationTransactionController;
|
|
108
108
|
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
109
|
+
/** @deprecated Legacy demo/OTP compatibility input. */
|
|
109
110
|
legalRepresentativePayload?: LegalOrganizationVerificationRepresentativePayload;
|
|
110
111
|
verification?: LegalOrganizationVerificationRouting;
|
|
111
112
|
attachments?: unknown[];
|
|
@@ -146,6 +147,7 @@ export interface LegalOrganizationOnboardingEditor {
|
|
|
146
147
|
buildVerificationTransactionInput(input: Readonly<{
|
|
147
148
|
controller: LegalOrganizationVerificationTransactionController;
|
|
148
149
|
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
150
|
+
/** @deprecated Legacy demo/OTP compatibility input. */
|
|
149
151
|
legalRepresentativePayload?: LegalOrganizationVerificationRepresentativePayload;
|
|
150
152
|
verification?: LegalOrganizationVerificationRouting;
|
|
151
153
|
attachments?: unknown[];
|
|
@@ -304,9 +304,7 @@ export function createLegalOrganizationOnboardingFacade() {
|
|
|
304
304
|
...(controllerEmail ? { email: controllerEmail } : {}),
|
|
305
305
|
...(representativeSameAs ? { sameAs: representativeSameAs } : {}),
|
|
306
306
|
}
|
|
307
|
-
:
|
|
308
|
-
? { email: controllerEmail }
|
|
309
|
-
: undefined,
|
|
307
|
+
: undefined,
|
|
310
308
|
verification: {
|
|
311
309
|
resourceType: normalizeOptionalText(input.verificationResourceType) || 'contract',
|
|
312
310
|
},
|
|
@@ -4,6 +4,27 @@ export type LegalOrganizationVerificationCredentialPair = Readonly<{
|
|
|
4
4
|
organizationCredential: LegalOrganizationVerificationCredential;
|
|
5
5
|
legalRepresentativeCredential: LegalOrganizationVerificationCredential;
|
|
6
6
|
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts the controller actor stored at
|
|
9
|
+
* `credentialSubject.owner` in an organization-controller service VC.
|
|
10
|
+
*
|
|
11
|
+
* @param credential Candidate organization-controller credential.
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractOrganizationControllerOwner(credential: unknown): Record<string, unknown> | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Extracts the stable public actor identifier from an
|
|
16
|
+
* organization-controller service VC.
|
|
17
|
+
*
|
|
18
|
+
* @param credential Candidate organization-controller credential.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractOrganizationControllerSameAs(credential: unknown): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Extracts the RFC 9278 JWK-thumbprint binding from an
|
|
23
|
+
* organization-controller service VC.
|
|
24
|
+
*
|
|
25
|
+
* @param credential Candidate organization-controller credential.
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractOrganizationControllerBinding(credential: unknown): string | undefined;
|
|
7
28
|
/**
|
|
8
29
|
* Returns the ICA verification entries currently projected by GW host
|
|
9
30
|
* legal-organization `_transaction`.
|
|
@@ -35,3 +56,27 @@ export declare function readLegalRepresentativeSameAsFromResponseBody(responseBo
|
|
|
35
56
|
* legal-representative credential when present.
|
|
36
57
|
*/
|
|
37
58
|
export declare function readLegalRepresentativeBindingFromResponseBody(responseBody: unknown): string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Returns all independently issued organization-controller service
|
|
61
|
+
* credentials in an ICA or projected GW verification response.
|
|
62
|
+
*
|
|
63
|
+
* The result is empty when the response contains only the legacy organization
|
|
64
|
+
* and legal-representative credential pair.
|
|
65
|
+
*/
|
|
66
|
+
export declare function readOrganizationControllerCredentialsFromResponseBody(responseBody: unknown): LegalOrganizationVerificationCredential[];
|
|
67
|
+
/**
|
|
68
|
+
* Returns one organization-controller service credential in an ICA or
|
|
69
|
+
* projected GW verification response. Pass a stable actor `sameAs` to select
|
|
70
|
+
* one controller independently; otherwise the first controller is returned.
|
|
71
|
+
*/
|
|
72
|
+
export declare function readOrganizationControllerCredentialFromResponseBody(responseBody: unknown, controllerSameAs?: string): LegalOrganizationVerificationCredential | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Reads `credentialSubject.owner.sameAs` from the first
|
|
75
|
+
* organization-controller service credential when present.
|
|
76
|
+
*/
|
|
77
|
+
export declare function readOrganizationControllerSameAsFromResponseBody(responseBody: unknown): string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Reads `credentialSubject.owner.hasCredential.material` from the first
|
|
80
|
+
* organization-controller service credential when present.
|
|
81
|
+
*/
|
|
82
|
+
export declare function readOrganizationControllerBindingFromResponseBody(responseBody: unknown): string | undefined;
|
|
@@ -23,6 +23,45 @@ function findCredentialResource(entries, expectedTypeFragment, fallbackIndex) {
|
|
|
23
23
|
}
|
|
24
24
|
return resource;
|
|
25
25
|
}
|
|
26
|
+
function hasCredentialType(value, expectedType) {
|
|
27
|
+
const candidate = asObject(value);
|
|
28
|
+
const resource = asObject(candidate?.resource);
|
|
29
|
+
const typeValues = [candidate?.type, resource?.type];
|
|
30
|
+
return typeValues.some((typeValue) => {
|
|
31
|
+
const tokens = Array.isArray(typeValue)
|
|
32
|
+
? typeValue.map((token) => String(token || ''))
|
|
33
|
+
: [String(typeValue || '')];
|
|
34
|
+
return tokens.some((token) => token.includes(expectedType));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extracts the controller actor stored at
|
|
39
|
+
* `credentialSubject.owner` in an organization-controller service VC.
|
|
40
|
+
*
|
|
41
|
+
* @param credential Candidate organization-controller credential.
|
|
42
|
+
*/
|
|
43
|
+
export function extractOrganizationControllerOwner(credential) {
|
|
44
|
+
return asObject(extractCredentialSubject(credential)?.owner);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extracts the stable public actor identifier from an
|
|
48
|
+
* organization-controller service VC.
|
|
49
|
+
*
|
|
50
|
+
* @param credential Candidate organization-controller credential.
|
|
51
|
+
*/
|
|
52
|
+
export function extractOrganizationControllerSameAs(credential) {
|
|
53
|
+
return String(extractOrganizationControllerOwner(credential)?.sameAs || '').trim() || undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Extracts the RFC 9278 JWK-thumbprint binding from an
|
|
57
|
+
* organization-controller service VC.
|
|
58
|
+
*
|
|
59
|
+
* @param credential Candidate organization-controller credential.
|
|
60
|
+
*/
|
|
61
|
+
export function extractOrganizationControllerBinding(credential) {
|
|
62
|
+
const owner = extractOrganizationControllerOwner(credential);
|
|
63
|
+
return owner ? extractRepresentativeCredentialBinding({ credentialSubject: owner }) : undefined;
|
|
64
|
+
}
|
|
26
65
|
/**
|
|
27
66
|
* Returns the ICA verification entries currently projected by GW host
|
|
28
67
|
* legal-organization `_transaction`.
|
|
@@ -104,3 +143,42 @@ export function readLegalRepresentativeBindingFromResponseBody(responseBody) {
|
|
|
104
143
|
const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
|
|
105
144
|
return extractRepresentativeCredentialBinding(pair.legalRepresentativeCredential);
|
|
106
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns all independently issued organization-controller service
|
|
148
|
+
* credentials in an ICA or projected GW verification response.
|
|
149
|
+
*
|
|
150
|
+
* The result is empty when the response contains only the legacy organization
|
|
151
|
+
* and legal-representative credential pair.
|
|
152
|
+
*/
|
|
153
|
+
export function readOrganizationControllerCredentialsFromResponseBody(responseBody) {
|
|
154
|
+
return getLegalOrganizationVerificationEntriesFromResponseBody(responseBody)
|
|
155
|
+
.filter((entry) => hasCredentialType(entry, 'OrganizationControllerCredential'))
|
|
156
|
+
.map((entry) => asObject(asObject(entry)?.resource) || asObject(entry))
|
|
157
|
+
.filter((entry) => Boolean(entry));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Returns one organization-controller service credential in an ICA or
|
|
161
|
+
* projected GW verification response. Pass a stable actor `sameAs` to select
|
|
162
|
+
* one controller independently; otherwise the first controller is returned.
|
|
163
|
+
*/
|
|
164
|
+
export function readOrganizationControllerCredentialFromResponseBody(responseBody, controllerSameAs) {
|
|
165
|
+
const credentials = readOrganizationControllerCredentialsFromResponseBody(responseBody);
|
|
166
|
+
const expectedSameAs = String(controllerSameAs || '').trim();
|
|
167
|
+
return expectedSameAs
|
|
168
|
+
? credentials.find((credential) => extractOrganizationControllerSameAs(credential) === expectedSameAs)
|
|
169
|
+
: credentials[0];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Reads `credentialSubject.owner.sameAs` from the first
|
|
173
|
+
* organization-controller service credential when present.
|
|
174
|
+
*/
|
|
175
|
+
export function readOrganizationControllerSameAsFromResponseBody(responseBody) {
|
|
176
|
+
return extractOrganizationControllerSameAs(readOrganizationControllerCredentialFromResponseBody(responseBody));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Reads `credentialSubject.owner.hasCredential.material` from the first
|
|
180
|
+
* organization-controller service credential when present.
|
|
181
|
+
*/
|
|
182
|
+
export function readOrganizationControllerBindingFromResponseBody(responseBody) {
|
|
183
|
+
return extractOrganizationControllerBinding(readOrganizationControllerCredentialFromResponseBody(responseBody));
|
|
184
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BundleJsonApi } from '../models/bundle';
|
|
2
2
|
import type { ClaimsRecord } from '../models/resource-document';
|
|
3
|
+
import type { VerifiableCredentialV2 } from '../models/verifiable-credential';
|
|
3
4
|
/**
|
|
4
5
|
* Canonical business entry type for the first host-side onboarding step that
|
|
5
6
|
* asks GW CORE to forward a legal-organization verification request to ICA.
|
|
@@ -71,8 +72,14 @@ export type LegalOrganizationVerificationTransactionInput = Readonly<{
|
|
|
71
72
|
claims: ClaimsRecord;
|
|
72
73
|
controller: LegalOrganizationVerificationTransactionController;
|
|
73
74
|
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
75
|
+
/**
|
|
76
|
+
* @deprecated Legacy demo/OTP compatibility only. Canonical signed-PDF and
|
|
77
|
+
* strict flows derive the representative from verified evidence.
|
|
78
|
+
*/
|
|
74
79
|
legalRepresentativePayload?: LegalOrganizationVerificationRepresentativePayload;
|
|
75
80
|
verification?: LegalOrganizationVerificationRouting;
|
|
81
|
+
/** Out-of-band host authorization used only by the Test Network path. */
|
|
82
|
+
authorizationCredential?: VerifiableCredentialV2;
|
|
76
83
|
attachments?: unknown[];
|
|
77
84
|
}>;
|
|
78
85
|
export type LegalOrganizationVerificationTransactionEntry = Readonly<{
|
|
@@ -84,9 +91,12 @@ export type LegalOrganizationVerificationTransactionEntry = Readonly<{
|
|
|
84
91
|
resource?: {
|
|
85
92
|
controller?: LegalOrganizationVerificationTransactionController;
|
|
86
93
|
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
94
|
+
/** @deprecated Legacy demo/OTP compatibility input. */
|
|
87
95
|
legalRepresentativePayload?: LegalOrganizationVerificationRepresentativePayload;
|
|
96
|
+
/** @deprecated Legacy ICA wire alias accepted only while migrating old callers. */
|
|
88
97
|
legalRepresentative?: LegalOrganizationVerificationRepresentativePayload;
|
|
89
98
|
verification?: LegalOrganizationVerificationRouting;
|
|
99
|
+
authorizationCredential?: VerifiableCredentialV2;
|
|
90
100
|
[key: string]: unknown;
|
|
91
101
|
};
|
|
92
102
|
[key: string]: unknown;
|
|
@@ -122,6 +132,9 @@ export declare function getLegalOrganizationVerificationController(value: unknow
|
|
|
122
132
|
* Returns the normalized legal representative contact payload from the first
|
|
123
133
|
* legal-organization verification transaction entry when present.
|
|
124
134
|
*
|
|
135
|
+
* @deprecated Read-only support for legacy demo/OTP payloads. Canonical
|
|
136
|
+
* signed-PDF and strict flows derive the representative from verified evidence.
|
|
137
|
+
*
|
|
125
138
|
* Compatibility note:
|
|
126
139
|
* - GW/SDK request builders use `resource.legalRepresentativePayload`
|
|
127
140
|
* - the ICA forwarding payload currently uses `resource.legalRepresentative`
|
|
@@ -61,6 +61,9 @@ export function buildLegalOrganizationVerificationTransactionBundle(input) {
|
|
|
61
61
|
verification: {
|
|
62
62
|
resourceType: normalizeText(input.verification?.resourceType) || 'contract',
|
|
63
63
|
},
|
|
64
|
+
...(input.authorizationCredential
|
|
65
|
+
? { authorizationCredential: input.authorizationCredential }
|
|
66
|
+
: {}),
|
|
64
67
|
},
|
|
65
68
|
}],
|
|
66
69
|
...(Array.isArray(input.attachments) && input.attachments.length > 0
|
|
@@ -98,6 +101,9 @@ export function getLegalOrganizationVerificationController(value) {
|
|
|
98
101
|
* Returns the normalized legal representative contact payload from the first
|
|
99
102
|
* legal-organization verification transaction entry when present.
|
|
100
103
|
*
|
|
104
|
+
* @deprecated Read-only support for legacy demo/OTP payloads. Canonical
|
|
105
|
+
* signed-PDF and strict flows derive the representative from verified evidence.
|
|
106
|
+
*
|
|
101
107
|
* Compatibility note:
|
|
102
108
|
* - GW/SDK request builders use `resource.legalRepresentativePayload`
|
|
103
109
|
* - the ICA forwarding payload currently uses `resource.legalRepresentative`
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { VerifiableCredentialV2 } from '../models/verifiable-credential';
|
|
2
|
+
/** Lifecycle of the one GW activation licence delivered to the legal postal address. */
|
|
3
|
+
export declare const PostalActivationLicenseStatuses: Readonly<{
|
|
4
|
+
readonly Issued: "issued";
|
|
5
|
+
readonly Delivered: "delivered";
|
|
6
|
+
readonly Redeemed: "redeemed";
|
|
7
|
+
readonly Revoked: "revoked";
|
|
8
|
+
readonly Expired: "expired";
|
|
9
|
+
}>;
|
|
10
|
+
export type PostalActivationLicenseStatus = typeof PostalActivationLicenseStatuses[keyof typeof PostalActivationLicenseStatuses];
|
|
11
|
+
/**
|
|
12
|
+
* Public binding recorded for the activation licence. The activation code is
|
|
13
|
+
* deliberately absent: storage implementations retain only its protected
|
|
14
|
+
* value/index and never place the secret inside a VC.
|
|
15
|
+
*/
|
|
16
|
+
export type PostalActivationLicenseBinding = Readonly<{
|
|
17
|
+
licenseId: string;
|
|
18
|
+
applicationId: string;
|
|
19
|
+
organizationIdentifier: string;
|
|
20
|
+
controllerEmail: string;
|
|
21
|
+
controllerKeyMaterial: string;
|
|
22
|
+
postalAddressHash: string;
|
|
23
|
+
hostDid: string;
|
|
24
|
+
network: 'test-network' | 'network';
|
|
25
|
+
status: PostalActivationLicenseStatus;
|
|
26
|
+
issuedAt: string;
|
|
27
|
+
expiresAt: string;
|
|
28
|
+
deliveredAt?: string;
|
|
29
|
+
redeemedAt?: string;
|
|
30
|
+
}>;
|
|
31
|
+
/** Input for the credential returned out-of-band to the applicant controller. */
|
|
32
|
+
export type OrganizationRegistrationAuthorizationCredentialInput = Readonly<{
|
|
33
|
+
issuerDid: string;
|
|
34
|
+
subjectDid: string;
|
|
35
|
+
credentialId: string;
|
|
36
|
+
validFrom: string;
|
|
37
|
+
validUntil: string;
|
|
38
|
+
legalName: string;
|
|
39
|
+
organizationIdentifier: string;
|
|
40
|
+
controllerEmail: string;
|
|
41
|
+
controllerKeyMaterial: string;
|
|
42
|
+
applicationId: string;
|
|
43
|
+
accessPath: 'partner' | 'test-network';
|
|
44
|
+
targetNetwork: 'test-network' | 'network';
|
|
45
|
+
postalLicense: PostalActivationLicenseBinding;
|
|
46
|
+
proof?: VerifiableCredentialV2['proof'];
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Builds the immutable VC that a controller receives out-of-band and attaches
|
|
50
|
+
* to `Organization/_transaction`. The postal code itself never appears in the
|
|
51
|
+
* credential; its confirmed, purpose-bound licence record is referenced.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildOrganizationRegistrationAuthorizationCredential(input: OrganizationRegistrationAuthorizationCredentialInput): VerifiableCredentialV2;
|
|
54
|
+
/**
|
|
55
|
+
* Applies the only legal state transitions for the purpose-bound postal code.
|
|
56
|
+
* Confirmation proves delivery but deliberately does not consume the code;
|
|
57
|
+
* redemption occurs later during `_exchange`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function transitionPostalActivationLicense(current: PostalActivationLicenseStatus, action: 'mark_delivered' | 'redeem' | 'revoke' | 'expire'): PostalActivationLicenseStatus;
|
|
60
|
+
/**
|
|
61
|
+
* Produces deterministic UTF-8 JSON for detached proofs. Every proof signs the
|
|
62
|
+
* same credential payload with the complete `proof` property removed, so a
|
|
63
|
+
* later counter-proof cannot invalidate an earlier one.
|
|
64
|
+
*/
|
|
65
|
+
export declare function canonicalizeOrganizationRegistrationAuthorizationCredential(credential: VerifiableCredentialV2): string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ContractCredentialTypes, W3cCredentialContexts, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
|
|
2
|
+
/** Lifecycle of the one GW activation licence delivered to the legal postal address. */
|
|
3
|
+
export const PostalActivationLicenseStatuses = Object.freeze({
|
|
4
|
+
Issued: 'issued',
|
|
5
|
+
Delivered: 'delivered',
|
|
6
|
+
Redeemed: 'redeemed',
|
|
7
|
+
Revoked: 'revoked',
|
|
8
|
+
Expired: 'expired',
|
|
9
|
+
});
|
|
10
|
+
function required(value, name) {
|
|
11
|
+
const normalized = String(value || '').trim();
|
|
12
|
+
if (!normalized)
|
|
13
|
+
throw new Error(`Organization registration authorization requires ${name}.`);
|
|
14
|
+
return normalized;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Builds the immutable VC that a controller receives out-of-band and attaches
|
|
18
|
+
* to `Organization/_transaction`. The postal code itself never appears in the
|
|
19
|
+
* credential; its confirmed, purpose-bound licence record is referenced.
|
|
20
|
+
*/
|
|
21
|
+
export function buildOrganizationRegistrationAuthorizationCredential(input) {
|
|
22
|
+
const applicationId = required(input.applicationId, 'applicationId');
|
|
23
|
+
const organizationIdentifier = required(input.organizationIdentifier, 'organizationIdentifier');
|
|
24
|
+
const controllerEmail = required(input.controllerEmail, 'controllerEmail').toLowerCase();
|
|
25
|
+
if (input.postalLicense.status !== PostalActivationLicenseStatuses.Delivered) {
|
|
26
|
+
throw new Error('Organization registration authorization requires a delivered postal activation licence.');
|
|
27
|
+
}
|
|
28
|
+
if (input.postalLicense.applicationId !== applicationId
|
|
29
|
+
|| input.postalLicense.organizationIdentifier !== organizationIdentifier
|
|
30
|
+
|| input.postalLicense.controllerEmail.trim().toLowerCase() !== controllerEmail
|
|
31
|
+
|| input.postalLicense.controllerKeyMaterial !== input.controllerKeyMaterial
|
|
32
|
+
|| input.postalLicense.network !== input.targetNetwork) {
|
|
33
|
+
throw new Error('Postal activation licence does not match the organization registration application.');
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
'@context': [W3cCredentialContexts.V2, 'https://schema.org'],
|
|
37
|
+
id: required(input.credentialId, 'credentialId'),
|
|
38
|
+
type: [
|
|
39
|
+
W3cCredentialTypes.VerifiableCredential,
|
|
40
|
+
ContractCredentialTypes.OrganizationRegistrationAuthorizationCredential,
|
|
41
|
+
],
|
|
42
|
+
issuer: required(input.issuerDid, 'issuerDid'),
|
|
43
|
+
credentialSubject: {
|
|
44
|
+
id: required(input.subjectDid, 'subjectDid'),
|
|
45
|
+
applicationId,
|
|
46
|
+
accessPath: input.accessPath,
|
|
47
|
+
targetNetwork: input.targetNetwork,
|
|
48
|
+
organization: {
|
|
49
|
+
legalName: required(input.legalName, 'legalName'),
|
|
50
|
+
identifier: organizationIdentifier,
|
|
51
|
+
},
|
|
52
|
+
controller: {
|
|
53
|
+
email: controllerEmail,
|
|
54
|
+
hasCredential: { material: required(input.controllerKeyMaterial, 'controllerKeyMaterial') },
|
|
55
|
+
},
|
|
56
|
+
postalActivationLicense: {
|
|
57
|
+
id: required(input.postalLicense.licenseId, 'postalLicense.licenseId'),
|
|
58
|
+
status: input.postalLicense.status,
|
|
59
|
+
postalAddressHash: required(input.postalLicense.postalAddressHash, 'postalLicense.postalAddressHash'),
|
|
60
|
+
deliveredAt: required(input.postalLicense.deliveredAt, 'postalLicense.deliveredAt'),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
validFrom: required(input.validFrom, 'validFrom'),
|
|
64
|
+
validUntil: required(input.validUntil, 'validUntil'),
|
|
65
|
+
...(input.proof ? { proof: input.proof } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Applies the only legal state transitions for the purpose-bound postal code.
|
|
70
|
+
* Confirmation proves delivery but deliberately does not consume the code;
|
|
71
|
+
* redemption occurs later during `_exchange`.
|
|
72
|
+
*/
|
|
73
|
+
export function transitionPostalActivationLicense(current, action) {
|
|
74
|
+
if (action === 'mark_delivered' && current === PostalActivationLicenseStatuses.Issued) {
|
|
75
|
+
return PostalActivationLicenseStatuses.Delivered;
|
|
76
|
+
}
|
|
77
|
+
if (action === 'redeem' && current === PostalActivationLicenseStatuses.Delivered) {
|
|
78
|
+
return PostalActivationLicenseStatuses.Redeemed;
|
|
79
|
+
}
|
|
80
|
+
if (action === 'revoke'
|
|
81
|
+
&& (current === PostalActivationLicenseStatuses.Issued
|
|
82
|
+
|| current === PostalActivationLicenseStatuses.Delivered)) {
|
|
83
|
+
return PostalActivationLicenseStatuses.Revoked;
|
|
84
|
+
}
|
|
85
|
+
if (action === 'expire'
|
|
86
|
+
&& (current === PostalActivationLicenseStatuses.Issued
|
|
87
|
+
|| current === PostalActivationLicenseStatuses.Delivered)) {
|
|
88
|
+
return PostalActivationLicenseStatuses.Expired;
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`Invalid postal activation licence transition: ${current} -> ${action}.`);
|
|
91
|
+
}
|
|
92
|
+
function canonicalizeValue(value) {
|
|
93
|
+
if (Array.isArray(value))
|
|
94
|
+
return value.map(canonicalizeValue);
|
|
95
|
+
if (!value || typeof value !== 'object')
|
|
96
|
+
return value;
|
|
97
|
+
return Object.fromEntries(Object.entries(value)
|
|
98
|
+
.filter(([key]) => key !== 'proof')
|
|
99
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
100
|
+
.map(([key, nested]) => [key, canonicalizeValue(nested)]));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Produces deterministic UTF-8 JSON for detached proofs. Every proof signs the
|
|
104
|
+
* same credential payload with the complete `proof` property removed, so a
|
|
105
|
+
* later counter-proof cannot invalidate an earlier one.
|
|
106
|
+
*/
|
|
107
|
+
export function canonicalizeOrganizationRegistrationAuthorizationCredential(credential) {
|
|
108
|
+
if (!credential.type.includes(ContractCredentialTypes.OrganizationRegistrationAuthorizationCredential)) {
|
|
109
|
+
throw new Error('Credential is not an organization registration authorization.');
|
|
110
|
+
}
|
|
111
|
+
return JSON.stringify(canonicalizeValue(credential));
|
|
112
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { BundleEntry } from '../models/bundle';
|
|
2
|
+
import type { SubjectIdentityAssociation, SubjectIdentityBundleEntry, SubjectIdentityInput } from '../models/subject-identity';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the exact UTF-8 token used by the distributed Subject lookup.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - canonical input is `codingSystem|jurisdiction-or-empty|codeValue`;
|
|
8
|
+
* - an empty jurisdiction is explicit, producing `||` for global identifiers;
|
|
9
|
+
* - values use the existing individual-identifier uppercase normalization;
|
|
10
|
+
* - `|` is forbidden in every component to keep the encoding unambiguous.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildSubjectIdentifierToken(input: Pick<SubjectIdentityInput, 'codingSystem' | 'jurisdiction' | 'codeValue'>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Returns `urn:multibase:<base58btc multihash>` using SHA3-384.
|
|
15
|
+
*
|
|
16
|
+
* The value is a deterministic public lookup key, not an authorization proof.
|
|
17
|
+
* The raw identifier remains in the encrypted Subject collection and is never
|
|
18
|
+
* included in the Fabric payload.
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildSubjectIdentifierAssetId(input: Pick<SubjectIdentityInput, 'codingSystem' | 'jurisdiction' | 'codeValue'>): string;
|
|
21
|
+
/**
|
|
22
|
+
* Builds one semantic identity resource for the neutral Subject collection.
|
|
23
|
+
*
|
|
24
|
+
* `sameAs` always identifies the stable public unified card. The private
|
|
25
|
+
* coding system and code value remain claims of Person, Animal or Place; the
|
|
26
|
+
* collection name never replaces that semantic resource type.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildSubjectIdentityBundleEntry(input: SubjectIdentityInput): SubjectIdentityBundleEntry;
|
|
29
|
+
/** Reads and validates one Person/Animal/Place entry from the Subject collection. */
|
|
30
|
+
export declare function readSubjectIdentityBundleEntry(entry: BundleEntry): SubjectIdentityAssociation;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { UrnPrefixes } from '../constants/urn.js';
|
|
2
|
+
import { encodeMultibaseSha3 } from './multibasehash.js';
|
|
3
|
+
import { normalizeIndividualIdentifierType } from './individual-identifier.js';
|
|
4
|
+
const SUBJECT_RESOURCE_BY_KIND = {
|
|
5
|
+
person: 'Person',
|
|
6
|
+
animal: 'Animal',
|
|
7
|
+
property: 'Place',
|
|
8
|
+
};
|
|
9
|
+
const SUBJECT_KIND_BY_RESOURCE = {
|
|
10
|
+
Person: 'person',
|
|
11
|
+
Animal: 'animal',
|
|
12
|
+
Place: 'property',
|
|
13
|
+
};
|
|
14
|
+
const STABLE_CARD_ID_PATTERN = /^(?:did|urn|https):\S+$/i;
|
|
15
|
+
const ISO_3166_JURISDICTION_PATTERN = /^[A-Z]{2}(?:-[A-Z0-9]{1,3})?$/;
|
|
16
|
+
/**
|
|
17
|
+
* Builds the exact UTF-8 token used by the distributed Subject lookup.
|
|
18
|
+
*
|
|
19
|
+
* Contract:
|
|
20
|
+
* - canonical input is `codingSystem|jurisdiction-or-empty|codeValue`;
|
|
21
|
+
* - an empty jurisdiction is explicit, producing `||` for global identifiers;
|
|
22
|
+
* - values use the existing individual-identifier uppercase normalization;
|
|
23
|
+
* - `|` is forbidden in every component to keep the encoding unambiguous.
|
|
24
|
+
*/
|
|
25
|
+
export function buildSubjectIdentifierToken(input) {
|
|
26
|
+
const codingSystem = normalizeTokenPart(input.codingSystem, 'codingSystem');
|
|
27
|
+
const jurisdiction = normalizeJurisdiction(input.jurisdiction);
|
|
28
|
+
const codeValue = normalizeTokenPart(input.codeValue, 'codeValue').toUpperCase();
|
|
29
|
+
return `${codingSystem}|${jurisdiction}|${codeValue}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns `urn:multibase:<base58btc multihash>` using SHA3-384.
|
|
33
|
+
*
|
|
34
|
+
* The value is a deterministic public lookup key, not an authorization proof.
|
|
35
|
+
* The raw identifier remains in the encrypted Subject collection and is never
|
|
36
|
+
* included in the Fabric payload.
|
|
37
|
+
*/
|
|
38
|
+
export function buildSubjectIdentifierAssetId(input) {
|
|
39
|
+
return `${UrnPrefixes.Multibase}${encodeMultibaseSha3(buildSubjectIdentifierToken(input), 384)}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Builds one semantic identity resource for the neutral Subject collection.
|
|
43
|
+
*
|
|
44
|
+
* `sameAs` always identifies the stable public unified card. The private
|
|
45
|
+
* coding system and code value remain claims of Person, Animal or Place; the
|
|
46
|
+
* collection name never replaces that semantic resource type.
|
|
47
|
+
*/
|
|
48
|
+
export function buildSubjectIdentityBundleEntry(input) {
|
|
49
|
+
const resourceType = SUBJECT_RESOURCE_BY_KIND[input.subjectKind];
|
|
50
|
+
if (!resourceType)
|
|
51
|
+
throw new TypeError(`Unsupported subject kind: ${input.subjectKind}`);
|
|
52
|
+
const cardId = input.cardId.trim();
|
|
53
|
+
if (!STABLE_CARD_ID_PATTERN.test(cardId)) {
|
|
54
|
+
throw new TypeError('Subject identity cardId must be a stable URI (did:, urn: or https:).');
|
|
55
|
+
}
|
|
56
|
+
const codingSystem = input.subjectKind === 'person'
|
|
57
|
+
? normalizeIndividualIdentifierType(input.codingSystem)
|
|
58
|
+
: normalizeTokenPart(input.codingSystem, 'codingSystem');
|
|
59
|
+
const jurisdiction = normalizeJurisdiction(input.jurisdiction);
|
|
60
|
+
if (input.subjectKind === 'person' && !jurisdiction) {
|
|
61
|
+
throw new TypeError('Person identity jurisdiction is required.');
|
|
62
|
+
}
|
|
63
|
+
const codeValue = normalizeTokenPart(input.codeValue, 'codeValue').toUpperCase();
|
|
64
|
+
const assetId = buildSubjectIdentifierAssetId({ codingSystem, jurisdiction, codeValue });
|
|
65
|
+
const claimPrefix = `org.schema.${resourceType}`;
|
|
66
|
+
return {
|
|
67
|
+
id: assetId,
|
|
68
|
+
fullUrl: assetId,
|
|
69
|
+
type: 'Subject-identity-link-v1.0',
|
|
70
|
+
resource: {
|
|
71
|
+
resourceType,
|
|
72
|
+
id: assetId,
|
|
73
|
+
meta: {
|
|
74
|
+
claims: {
|
|
75
|
+
...(input.additionalClaims || {}),
|
|
76
|
+
[`${claimPrefix}.identifier`]: assetId,
|
|
77
|
+
[`${claimPrefix}.identifier.additionalType`]: codingSystem,
|
|
78
|
+
[`${claimPrefix}.identifier.jurisdiction`]: jurisdiction,
|
|
79
|
+
[`${claimPrefix}.identifier.value`]: codeValue,
|
|
80
|
+
[`${claimPrefix}.sameAs`]: cardId,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
request: { method: 'POST', url: 'Subject' },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Reads and validates one Person/Animal/Place entry from the Subject collection. */
|
|
88
|
+
export function readSubjectIdentityBundleEntry(entry) {
|
|
89
|
+
const resourceType = String(entry.resource?.resourceType || '');
|
|
90
|
+
const subjectKind = SUBJECT_KIND_BY_RESOURCE[resourceType];
|
|
91
|
+
if (!subjectKind) {
|
|
92
|
+
throw new TypeError(`Unsupported Subject identity resourceType: ${resourceType || '(missing)'}; expected Person, Animal or Place.`);
|
|
93
|
+
}
|
|
94
|
+
const claims = entry.resource?.meta?.claims || {};
|
|
95
|
+
const prefix = `org.schema.${resourceType}`;
|
|
96
|
+
const cardId = String(claims[`${prefix}.sameAs`] || '').trim();
|
|
97
|
+
const codingSystem = String(claims[`${prefix}.identifier.additionalType`] || '').trim();
|
|
98
|
+
const jurisdiction = normalizeJurisdiction(String(claims[`${prefix}.identifier.jurisdiction`] || ''));
|
|
99
|
+
const codeValue = String(claims[`${prefix}.identifier.value`] || '').trim();
|
|
100
|
+
if (!STABLE_CARD_ID_PATTERN.test(cardId))
|
|
101
|
+
throw new TypeError('Subject identity sameAs must contain one stable card URI.');
|
|
102
|
+
if (subjectKind === 'person' && !jurisdiction)
|
|
103
|
+
throw new TypeError('Person identity jurisdiction is required.');
|
|
104
|
+
const assetId = buildSubjectIdentifierAssetId({ codingSystem, jurisdiction, codeValue });
|
|
105
|
+
const claimedAssetId = String(claims[`${prefix}.identifier`] || entry.resource?.id || entry.id || '').trim();
|
|
106
|
+
if (claimedAssetId && claimedAssetId !== assetId) {
|
|
107
|
+
throw new TypeError('Subject identity identifier does not match codingSystem|jurisdiction|codeValue.');
|
|
108
|
+
}
|
|
109
|
+
return { subjectKind, resourceType, cardId, codingSystem, jurisdiction, codeValue, assetId };
|
|
110
|
+
}
|
|
111
|
+
function normalizeTokenPart(value, field) {
|
|
112
|
+
const normalized = String(value || '').trim().normalize('NFKC');
|
|
113
|
+
if (!normalized)
|
|
114
|
+
throw new TypeError(`${field} is required`);
|
|
115
|
+
if (normalized.includes('|'))
|
|
116
|
+
throw new TypeError(`${field} must not contain the '|' delimiter`);
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
function normalizeJurisdiction(value) {
|
|
120
|
+
const normalized = String(value || '').trim().normalize('NFKC').toUpperCase();
|
|
121
|
+
if (normalized.includes('|'))
|
|
122
|
+
throw new TypeError("jurisdiction must not contain the '|' delimiter");
|
|
123
|
+
if (normalized && !ISO_3166_JURISDICTION_PATTERN.test(normalized)) {
|
|
124
|
+
throw new TypeError(`Invalid ISO 3166 jurisdiction: ${value}`);
|
|
125
|
+
}
|
|
126
|
+
return normalized;
|
|
127
|
+
}
|