gdc-common-utils-ts 2.5.2 → 2.5.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 +3 -2
- package/dist/constants/device.d.ts +6 -0
- package/dist/constants/device.js +5 -0
- package/dist/constants/employee-lifecycle.d.ts +52 -0
- package/dist/constants/employee-lifecycle.js +48 -0
- package/dist/constants/http.d.ts +28 -0
- package/dist/constants/http.js +28 -0
- package/dist/constants/identity-auth.d.ts +57 -0
- package/dist/constants/identity-auth.js +57 -0
- package/dist/constants/index.d.ts +4 -0
- package/dist/constants/index.js +4 -0
- package/dist/constants/organization-application.d.ts +27 -0
- package/dist/constants/organization-application.js +29 -0
- package/dist/constants/schemaorg.d.ts +4 -0
- package/dist/constants/schemaorg.js +4 -0
- package/dist/constants/verifiable-credentials.d.ts +5 -1
- package/dist/constants/verifiable-credentials.js +6 -1
- package/dist/examples/ica-activation-proof.d.ts +31 -7
- package/dist/examples/ica-activation-proof.js +31 -7
- package/dist/examples/ica-verify-response.d.ts +57 -8
- package/dist/examples/ica-verify-response.js +82 -4
- package/dist/examples/inter-tenant-access-contract.d.ts +2 -0
- package/dist/examples/inter-tenant-access-contract.js +2 -0
- package/dist/examples/license.d.ts +111 -0
- package/dist/examples/license.js +85 -2
- package/dist/examples/shared.d.ts +33 -0
- package/dist/examples/shared.js +32 -0
- package/dist/models/device-license.d.ts +2 -2
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/inter-tenant-access-contract.d.ts +6 -0
- package/dist/models/inter-tenant-access-contract.js +6 -0
- package/dist/models/organization-employee-lifecycle.d.ts +45 -0
- package/dist/models/organization-employee-lifecycle.js +1 -0
- package/dist/models/urlPath.d.ts +1 -0
- package/dist/models/urlPath.js +1 -0
- package/dist/utils/activation-policy.d.ts +32 -10
- package/dist/utils/activation-policy.js +134 -17
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/inter-tenant-access-contract.js +16 -0
- package/dist/utils/jwk-thumbprint.d.ts +2 -0
- package/dist/utils/jwk-thumbprint.js +8 -0
- package/dist/utils/legal-organization-verification-result.d.ts +8 -0
- package/dist/utils/legal-organization-verification-result.js +10 -1
- package/dist/utils/legal-organization-verification-transaction.d.ts +6 -1
- package/dist/utils/legal-organization-verification-transaction.js +4 -4
- package/dist/utils/license.js +3 -3
- package/dist/utils/organization-employee-lifecycle.d.ts +12 -0
- package/dist/utils/organization-employee-lifecycle.js +125 -0
- package/dist/utils/vp-token.d.ts +5 -1
- package/dist/utils/vp-token.js +6 -2
- package/package.json +1 -1
package/dist/models/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export * from './dataspace-discovery.js';
|
|
|
19
19
|
export * from './dataspace-discovery-defaults.js';
|
|
20
20
|
export * from './dataspace-protocol.js';
|
|
21
21
|
export * from './device-license.js';
|
|
22
|
+
export * from './organization-employee-lifecycle.js';
|
|
22
23
|
export * from './did.js';
|
|
23
24
|
export * from './fhir-documents.js';
|
|
24
25
|
export * from './gaia-x.js';
|
|
@@ -16,6 +16,12 @@ export declare enum ClaimInterTenantAccessContract {
|
|
|
16
16
|
identifier = "Contract.identifier",
|
|
17
17
|
/** FHIR Contract lifecycle status, for example `executed` or `amended`. */
|
|
18
18
|
status = "Contract.status",
|
|
19
|
+
/**
|
|
20
|
+
* FHIR `Contract.type` CodeableConcept encoded as `system|code` in the flat
|
|
21
|
+
* claims transport. The terminology authority is supplied by the adopting
|
|
22
|
+
* governance domain rather than hardcoded in this product-neutral package.
|
|
23
|
+
*/
|
|
24
|
+
type = "Contract.type",
|
|
19
25
|
/** When the agreement was formally issued. */
|
|
20
26
|
issued = "Contract.issued",
|
|
21
27
|
/** Agreement validity start date/time. */
|
|
@@ -18,6 +18,12 @@ export var ClaimInterTenantAccessContract;
|
|
|
18
18
|
ClaimInterTenantAccessContract["identifier"] = "Contract.identifier";
|
|
19
19
|
/** FHIR Contract lifecycle status, for example `executed` or `amended`. */
|
|
20
20
|
ClaimInterTenantAccessContract["status"] = "Contract.status";
|
|
21
|
+
/**
|
|
22
|
+
* FHIR `Contract.type` CodeableConcept encoded as `system|code` in the flat
|
|
23
|
+
* claims transport. The terminology authority is supplied by the adopting
|
|
24
|
+
* governance domain rather than hardcoded in this product-neutral package.
|
|
25
|
+
*/
|
|
26
|
+
ClaimInterTenantAccessContract["type"] = "Contract.type";
|
|
21
27
|
/** When the agreement was formally issued. */
|
|
22
28
|
ClaimInterTenantAccessContract["issued"] = "Contract.issued";
|
|
23
29
|
/** Agreement validity start date/time. */
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { DeviceBindingStatus } from '../constants/device';
|
|
2
|
+
import type { EmployeeActivationGrantVersion, EmployeeDirectoryStatus } from '../constants/employee-lifecycle';
|
|
3
|
+
/** One installation in the controller-facing employee lifecycle projection. */
|
|
4
|
+
export type OrganizationEmployeeDeviceRecord = Readonly<{
|
|
5
|
+
clientId: string;
|
|
6
|
+
name: string;
|
|
7
|
+
status: DeviceBindingStatus;
|
|
8
|
+
}>;
|
|
9
|
+
/** License state attached to one employee directory entry. */
|
|
10
|
+
export type OrganizationEmployeeLicenseRecord = Readonly<{
|
|
11
|
+
id: string;
|
|
12
|
+
status: string;
|
|
13
|
+
maxDevices: number;
|
|
14
|
+
activeDevices: number;
|
|
15
|
+
devices: ReadonlyArray<OrganizationEmployeeDeviceRecord>;
|
|
16
|
+
}>;
|
|
17
|
+
/** Product-neutral employee, seat and installation lifecycle projection. */
|
|
18
|
+
export type OrganizationEmployeeLifecycleRecord = Readonly<{
|
|
19
|
+
resourceId: string;
|
|
20
|
+
email: string;
|
|
21
|
+
roleCode: string;
|
|
22
|
+
employeeDid: string;
|
|
23
|
+
status: EmployeeDirectoryStatus;
|
|
24
|
+
license?: OrganizationEmployeeLicenseRecord;
|
|
25
|
+
}>;
|
|
26
|
+
/** Typed wire request for revoking one installation without releasing its seat. */
|
|
27
|
+
export type EmployeeDeviceRevocationTarget = Readonly<{
|
|
28
|
+
licenseId: string;
|
|
29
|
+
clientId: string;
|
|
30
|
+
}>;
|
|
31
|
+
/** Tenant routing metadata bound to an employee activation credential digest. */
|
|
32
|
+
export type EmployeeActivationGrant = Readonly<{
|
|
33
|
+
version: EmployeeActivationGrantVersion;
|
|
34
|
+
employeeDid: string;
|
|
35
|
+
employeeRoleCode: string;
|
|
36
|
+
employeeActorIdentifier: string;
|
|
37
|
+
providerDid: string;
|
|
38
|
+
routeContext: Readonly<{
|
|
39
|
+
tenantId: string;
|
|
40
|
+
jurisdiction: string;
|
|
41
|
+
sector: string;
|
|
42
|
+
}>;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
expiresAt: string;
|
|
45
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/models/urlPath.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare enum Sector {
|
|
6
6
|
TEST = "test",// For mock/demo endpoints and host registry in tests
|
|
7
7
|
SYSTEM = "system",// Reserved for the host's bootstrap operation (TODO: deprecate)
|
|
8
|
+
ANTIFRAUD = "antifraud",
|
|
8
9
|
HEALTH_CARE = "health-care",
|
|
9
10
|
HEALTH_INSURANCE = "health-insurance",
|
|
10
11
|
EMERGENCY = "emergency",
|
package/dist/models/urlPath.js
CHANGED
|
@@ -8,6 +8,7 @@ export var Sector;
|
|
|
8
8
|
(function (Sector) {
|
|
9
9
|
Sector["TEST"] = "test";
|
|
10
10
|
Sector["SYSTEM"] = "system";
|
|
11
|
+
Sector["ANTIFRAUD"] = "antifraud";
|
|
11
12
|
Sector["HEALTH_CARE"] = "health-care";
|
|
12
13
|
Sector["HEALTH_INSURANCE"] = "health-insurance";
|
|
13
14
|
Sector["EMERGENCY"] = "emergency";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ActivationRepresentativePolicyErrorCode = 'MISSING_REPRESENTATIVE_SUBJECT_ID' | 'MISSING_REPRESENTATIVE_ROLE_RESPRSN' | 'MISSING_REPRESENTATIVE_CREDENTIAL_BINDING' | 'REPRESENTATIVE_TAXID_MISMATCH';
|
|
1
|
+
export type ActivationRepresentativePolicyErrorCode = 'MISSING_REPRESENTATIVE_SUBJECT_ID' | 'MISSING_REPRESENTATIVE_ROLE_RESPRSN' | 'MISSING_REPRESENTATIVE_CREDENTIAL_BINDING' | 'MISSING_CONTROLLER_ROLE_RESPRSN' | 'MISSING_CONTROLLER_CREDENTIAL_BINDING' | 'CONTROLLER_TAXID_MISMATCH' | 'REPRESENTATIVE_TAXID_MISMATCH';
|
|
2
2
|
export type ActivationServiceAuthorizationPolicyErrorCode = 'MISSING_ORGANIZATION_SERVICE_CATEGORY' | 'MISSING_ORGANIZATION_SERVICE_TYPE' | 'UNAUTHORIZED_ORGANIZATION_SERVICE_CATEGORY' | 'UNAUTHORIZED_ORGANIZATION_SERVICE_TYPE';
|
|
3
3
|
export type ActivationRepresentativePolicyError = {
|
|
4
4
|
code: ActivationRepresentativePolicyErrorCode;
|
|
@@ -38,6 +38,20 @@ export declare function extractRepresentativeMemberOfTaxId(representativeCredent
|
|
|
38
38
|
* @param representativeCredential Candidate representative credential.
|
|
39
39
|
*/
|
|
40
40
|
export declare function extractRepresentativeRoleCode(representativeCredential: unknown): string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Reads controller-authorization codes from an ICA-issued controller VC.
|
|
43
|
+
* Professional ISCO occupations are deliberately excluded.
|
|
44
|
+
*/
|
|
45
|
+
export declare function extractOrganizationControllerRoleCodes(controllerCredential: unknown): string[];
|
|
46
|
+
/** Canonical name for reading controller authority from a service-controller VC. */
|
|
47
|
+
export declare const extractServiceControllerRoleCodes: typeof extractOrganizationControllerRoleCodes;
|
|
48
|
+
/**
|
|
49
|
+
* Reads professional ISCO occupations from an ICA-issued controller VC as
|
|
50
|
+
* canonical `ISCO-08|code` tokens.
|
|
51
|
+
*/
|
|
52
|
+
export declare function extractOrganizationControllerOccupationCodes(controllerCredential: unknown): string[];
|
|
53
|
+
/** Canonical name for reading ISCO occupations from a service-controller VC. */
|
|
54
|
+
export declare const extractServiceControllerOccupationCodes: typeof extractOrganizationControllerOccupationCodes;
|
|
41
55
|
/**
|
|
42
56
|
* Checks whether a role code contains the required code, ignoring prefixes such as `SYSTEM|`.
|
|
43
57
|
*
|
|
@@ -154,22 +168,30 @@ export declare function buildMemberDidWeb(ownerDidWeb: string, memberId: string,
|
|
|
154
168
|
*/
|
|
155
169
|
export declare function isMemberDidWebUnderOwner(memberDidWeb: string, ownerDidWeb: string): boolean;
|
|
156
170
|
/**
|
|
157
|
-
* Validates
|
|
171
|
+
* Validates controller authorization for organization activation.
|
|
158
172
|
*
|
|
159
|
-
*
|
|
160
|
-
* - `
|
|
161
|
-
*
|
|
173
|
+
* Canonical three-credential flow:
|
|
174
|
+
* - `LegalRepresentativeCredential` proves legal representation and carries
|
|
175
|
+
* the representative's professional ISCO occupation
|
|
176
|
+
* - `ServiceControllerCredential` independently carries `RESPRSN` in
|
|
177
|
+
* `owner.additionalType` and `owner.hasCredential.material` for the
|
|
178
|
+
* controller actor key
|
|
162
179
|
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
180
|
+
* Legacy two-credential compatibility is deliberately narrow. When no
|
|
181
|
+
* no service-controller credential exists, the representative credential is
|
|
182
|
+
* accepted as the controller proof only if that old credential itself carries
|
|
183
|
+
* both `RESPRSN` and `hasCredential` binding material. A modern representative
|
|
184
|
+
* credential containing only an ISCO occupation such as `ISCO-08|1120` is not
|
|
185
|
+
* promoted to controller and fails this policy.
|
|
166
186
|
*
|
|
167
187
|
* @param input.organizationCredential Candidate organization credential.
|
|
168
|
-
* @param input.representativeCredential
|
|
169
|
-
* @param input.
|
|
188
|
+
* @param input.representativeCredential Legal-representative credential.
|
|
189
|
+
* @param input.controllerCredential Canonical controller-authority credential.
|
|
190
|
+
* @param input.requiredRoleCode Required controller role, defaults to `RESPRSN`.
|
|
170
191
|
*/
|
|
171
192
|
export declare function validateActivationRepresentativePolicy(input: {
|
|
172
193
|
organizationCredential?: unknown;
|
|
173
194
|
representativeCredential?: unknown;
|
|
195
|
+
controllerCredential?: unknown;
|
|
174
196
|
requiredRoleCode?: string;
|
|
175
197
|
}): ActivationRepresentativePolicyError[];
|
|
@@ -88,6 +88,91 @@ export function extractRepresentativeRoleCode(representativeCredential) {
|
|
|
88
88
|
}
|
|
89
89
|
return undefined;
|
|
90
90
|
}
|
|
91
|
+
function readOccupationEntries(value) {
|
|
92
|
+
const values = Array.isArray(value) ? value : value ? [value] : [];
|
|
93
|
+
return values.map((entry) => {
|
|
94
|
+
if (typeof entry === 'string')
|
|
95
|
+
return { identifier: entry };
|
|
96
|
+
return asObject(entry);
|
|
97
|
+
}).filter((entry) => Boolean(entry));
|
|
98
|
+
}
|
|
99
|
+
function readCodedIdentifier(entry) {
|
|
100
|
+
const identifier = entry.identifier;
|
|
101
|
+
if (typeof identifier === 'string') {
|
|
102
|
+
const token = identifier.trim();
|
|
103
|
+
const separator = token.lastIndexOf('|');
|
|
104
|
+
return separator >= 0
|
|
105
|
+
? { system: token.slice(0, separator), value: token.slice(separator + 1) }
|
|
106
|
+
: { value: token };
|
|
107
|
+
}
|
|
108
|
+
const coded = asObject(identifier) || {};
|
|
109
|
+
return {
|
|
110
|
+
system: String(coded.additionalType || coded.system || '').trim() || undefined,
|
|
111
|
+
value: String(coded.value || '').trim() || undefined,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Reads controller-authorization codes from an ICA-issued controller VC.
|
|
116
|
+
* Professional ISCO occupations are deliberately excluded.
|
|
117
|
+
*/
|
|
118
|
+
export function extractOrganizationControllerRoleCodes(controllerCredential) {
|
|
119
|
+
const subject = extractCredentialSubject(controllerCredential) || {};
|
|
120
|
+
const owner = asObject(subject.owner) || {};
|
|
121
|
+
const canonical = (Array.isArray(owner.additionalType) ? owner.additionalType : [owner.additionalType])
|
|
122
|
+
.map((value) => String(value || '').trim())
|
|
123
|
+
.filter(Boolean);
|
|
124
|
+
if (canonical.length)
|
|
125
|
+
return canonical;
|
|
126
|
+
return readOccupationEntries(owner.hasOccupation)
|
|
127
|
+
.filter((entry) => String(entry['@type'] || '').toLowerCase() === 'role'
|
|
128
|
+
|| readCodedIdentifier(entry).system?.toUpperCase() !== 'ISCO-08')
|
|
129
|
+
.map((entry) => readCodedIdentifier(entry).value)
|
|
130
|
+
.filter((value) => Boolean(value));
|
|
131
|
+
}
|
|
132
|
+
/** Canonical name for reading controller authority from a service-controller VC. */
|
|
133
|
+
export const extractServiceControllerRoleCodes = extractOrganizationControllerRoleCodes;
|
|
134
|
+
/**
|
|
135
|
+
* Reads professional ISCO occupations from an ICA-issued controller VC as
|
|
136
|
+
* canonical `ISCO-08|code` tokens.
|
|
137
|
+
*/
|
|
138
|
+
export function extractOrganizationControllerOccupationCodes(controllerCredential) {
|
|
139
|
+
const subject = extractCredentialSubject(controllerCredential) || {};
|
|
140
|
+
const owner = asObject(subject.owner) || {};
|
|
141
|
+
const occupation = asObject(owner.hasOccupation);
|
|
142
|
+
const occupationalCategory = occupation?.occupationalCategory;
|
|
143
|
+
const canonical = (Array.isArray(occupationalCategory) ? occupationalCategory : [occupationalCategory])
|
|
144
|
+
.map((value) => {
|
|
145
|
+
if (typeof value === 'string')
|
|
146
|
+
return value.trim();
|
|
147
|
+
const category = asObject(value) || {};
|
|
148
|
+
const codeValue = String(category.codeValue || '').trim();
|
|
149
|
+
const codeSet = asObject(category.inCodeSet) || {};
|
|
150
|
+
const system = String(codeSet.name || '').trim();
|
|
151
|
+
return codeValue ? `${system || 'ISCO-08'}|${codeValue}` : '';
|
|
152
|
+
})
|
|
153
|
+
.filter(Boolean);
|
|
154
|
+
if (canonical.length)
|
|
155
|
+
return canonical;
|
|
156
|
+
return readOccupationEntries(owner.hasOccupation)
|
|
157
|
+
.map(readCodedIdentifier)
|
|
158
|
+
.filter((identifier) => identifier.system?.toUpperCase() === 'ISCO-08' && identifier.value)
|
|
159
|
+
.map((identifier) => `ISCO-08|${identifier.value}`);
|
|
160
|
+
}
|
|
161
|
+
/** Canonical name for reading ISCO occupations from a service-controller VC. */
|
|
162
|
+
export const extractServiceControllerOccupationCodes = extractOrganizationControllerOccupationCodes;
|
|
163
|
+
function extractOrganizationControllerBinding(controllerCredential) {
|
|
164
|
+
const subject = extractCredentialSubject(controllerCredential) || {};
|
|
165
|
+
const owner = asObject(subject.owner) || {};
|
|
166
|
+
return extractCredentialBindingValue(owner.hasCredential);
|
|
167
|
+
}
|
|
168
|
+
function extractOrganizationControllerProviderTaxId(controllerCredential) {
|
|
169
|
+
const subject = extractCredentialSubject(controllerCredential) || {};
|
|
170
|
+
const provider = asObject(subject.provider) || {};
|
|
171
|
+
const identifier = asObject(provider.identifier);
|
|
172
|
+
return normalizeTaxIdentifier(provider.taxID)
|
|
173
|
+
|| normalizeTaxIdentifier(provider.taxId)
|
|
174
|
+
|| normalizeTaxIdentifier(identifier?.value);
|
|
175
|
+
}
|
|
91
176
|
/**
|
|
92
177
|
* Checks whether a role code contains the required code, ignoring prefixes such as `SYSTEM|`.
|
|
93
178
|
*
|
|
@@ -307,19 +392,26 @@ export function isMemberDidWebUnderOwner(memberDidWeb, ownerDidWeb) {
|
|
|
307
392
|
return did.startsWith(`${owner}:member:`);
|
|
308
393
|
}
|
|
309
394
|
/**
|
|
310
|
-
* Validates
|
|
395
|
+
* Validates controller authorization for organization activation.
|
|
311
396
|
*
|
|
312
|
-
*
|
|
313
|
-
* - `
|
|
314
|
-
*
|
|
397
|
+
* Canonical three-credential flow:
|
|
398
|
+
* - `LegalRepresentativeCredential` proves legal representation and carries
|
|
399
|
+
* the representative's professional ISCO occupation
|
|
400
|
+
* - `ServiceControllerCredential` independently carries `RESPRSN` in
|
|
401
|
+
* `owner.additionalType` and `owner.hasCredential.material` for the
|
|
402
|
+
* controller actor key
|
|
315
403
|
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
404
|
+
* Legacy two-credential compatibility is deliberately narrow. When no
|
|
405
|
+
* no service-controller credential exists, the representative credential is
|
|
406
|
+
* accepted as the controller proof only if that old credential itself carries
|
|
407
|
+
* both `RESPRSN` and `hasCredential` binding material. A modern representative
|
|
408
|
+
* credential containing only an ISCO occupation such as `ISCO-08|1120` is not
|
|
409
|
+
* promoted to controller and fails this policy.
|
|
319
410
|
*
|
|
320
411
|
* @param input.organizationCredential Candidate organization credential.
|
|
321
|
-
* @param input.representativeCredential
|
|
322
|
-
* @param input.
|
|
412
|
+
* @param input.representativeCredential Legal-representative credential.
|
|
413
|
+
* @param input.controllerCredential Canonical controller-authority credential.
|
|
414
|
+
* @param input.requiredRoleCode Required controller role, defaults to `RESPRSN`.
|
|
323
415
|
*/
|
|
324
416
|
export function validateActivationRepresentativePolicy(input) {
|
|
325
417
|
const errors = [];
|
|
@@ -332,16 +424,41 @@ export function validateActivationRepresentativePolicy(input) {
|
|
|
332
424
|
message: 'ICA-issued representative credential is missing credentialSubject.id.',
|
|
333
425
|
});
|
|
334
426
|
}
|
|
335
|
-
if (!input.representativeCredential)
|
|
336
|
-
return errors;
|
|
337
427
|
const orgTax = extractOrganizationTaxId(input.organizationCredential);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
428
|
+
if (input.representativeCredential) {
|
|
429
|
+
const repTax = extractRepresentativeMemberOfTaxId(input.representativeCredential);
|
|
430
|
+
if (orgTax && repTax && orgTax !== repTax) {
|
|
431
|
+
errors.push({
|
|
432
|
+
code: 'REPRESENTATIVE_TAXID_MISMATCH',
|
|
433
|
+
message: 'ICA-issued representative credential memberOf.taxID must match organization credential taxID.',
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (input.controllerCredential) {
|
|
438
|
+
const controllerTax = extractOrganizationControllerProviderTaxId(input.controllerCredential);
|
|
439
|
+
if (orgTax && controllerTax && orgTax !== controllerTax) {
|
|
440
|
+
errors.push({
|
|
441
|
+
code: 'CONTROLLER_TAXID_MISMATCH',
|
|
442
|
+
message: 'ICA-issued controller credential provider.taxID must match organization credential taxID.',
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
const controllerRoles = extractOrganizationControllerRoleCodes(input.controllerCredential);
|
|
446
|
+
if (!controllerRoles.some((role) => hasActivationRepresentativeRole(role, input.requiredRoleCode || 'RESPRSN'))) {
|
|
447
|
+
errors.push({
|
|
448
|
+
code: 'MISSING_CONTROLLER_ROLE_RESPRSN',
|
|
449
|
+
message: 'ICA-issued service controller credential must include RESPRSN in credentialSubject.owner.additionalType.',
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
if (!extractOrganizationControllerBinding(input.controllerCredential)) {
|
|
453
|
+
errors.push({
|
|
454
|
+
code: 'MISSING_CONTROLLER_CREDENTIAL_BINDING',
|
|
455
|
+
message: 'ICA-issued service controller credential is missing credentialSubject.owner.hasCredential binding data.',
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
return errors;
|
|
344
459
|
}
|
|
460
|
+
if (!input.representativeCredential)
|
|
461
|
+
return errors;
|
|
345
462
|
const roleCode = extractRepresentativeRoleCode(input.representativeCredential);
|
|
346
463
|
if (!hasActivationRepresentativeRole(roleCode, input.requiredRoleCode || 'RESPRSN')) {
|
|
347
464
|
errors.push({
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ export * from './individual-organization-claims';
|
|
|
67
67
|
export * from './inter-tenant-access-contract';
|
|
68
68
|
export * from './legal-organization-onboarding-editor';
|
|
69
69
|
export * from './organization-lifecycle';
|
|
70
|
+
export * from './organization-employee-lifecycle';
|
|
70
71
|
export * from './organization-did-binding';
|
|
71
72
|
export * from './organization-authorization-urn';
|
|
72
73
|
export * from './individual-organization-lifecycle';
|
package/dist/utils/index.js
CHANGED
|
@@ -67,6 +67,7 @@ export * from './individual-organization-claims.js';
|
|
|
67
67
|
export * from './inter-tenant-access-contract.js';
|
|
68
68
|
export * from './legal-organization-onboarding-editor.js';
|
|
69
69
|
export * from './organization-lifecycle.js';
|
|
70
|
+
export * from './organization-employee-lifecycle.js';
|
|
70
71
|
export * from './organization-did-binding.js';
|
|
71
72
|
export * from './organization-authorization-urn.js';
|
|
72
73
|
export * from './individual-organization-lifecycle.js';
|
|
@@ -15,6 +15,20 @@ function splitCsv(value) {
|
|
|
15
15
|
.map((item) => item.trim())
|
|
16
16
|
.filter(Boolean)));
|
|
17
17
|
}
|
|
18
|
+
function buildContractTypeCodeableConcept(value) {
|
|
19
|
+
const normalized = String(value || '').trim();
|
|
20
|
+
if (!normalized)
|
|
21
|
+
return undefined;
|
|
22
|
+
const separator = normalized.indexOf('|');
|
|
23
|
+
if (separator < 1 || separator === normalized.length - 1) {
|
|
24
|
+
return { text: normalized };
|
|
25
|
+
}
|
|
26
|
+
const system = normalized.slice(0, separator).trim();
|
|
27
|
+
const code = normalized.slice(separator + 1).trim();
|
|
28
|
+
if (!system || !code)
|
|
29
|
+
return { text: normalized };
|
|
30
|
+
return { coding: [{ system, code }] };
|
|
31
|
+
}
|
|
18
32
|
function readClaimWithAliases(claims, canonicalKey, aliases = []) {
|
|
19
33
|
const direct = String(claims[canonicalKey] || '').trim();
|
|
20
34
|
if (direct)
|
|
@@ -124,6 +138,7 @@ function normalizeNow(input) {
|
|
|
124
138
|
export function buildInterTenantAccessContractResource(claims) {
|
|
125
139
|
const identifier = readClaimWithAliases(claims, ClaimInterTenantAccessContract.identifier) || '';
|
|
126
140
|
const status = readClaimWithAliases(claims, ClaimInterTenantAccessContract.status) || 'executed';
|
|
141
|
+
const type = buildContractTypeCodeableConcept(readClaimWithAliases(claims, ClaimInterTenantAccessContract.type));
|
|
127
142
|
const issued = readClaimWithAliases(claims, ClaimInterTenantAccessContract.issued) || '';
|
|
128
143
|
const appliesStart = readClaimWithAliases(claims, ClaimInterTenantAccessContract.appliesStart, ['Contract.applies.start']) || '';
|
|
129
144
|
const appliesEnd = readClaimWithAliases(claims, ClaimInterTenantAccessContract.appliesEnd, ['Contract.applies.end']) || '';
|
|
@@ -139,6 +154,7 @@ export function buildInterTenantAccessContractResource(claims) {
|
|
|
139
154
|
id: identifier || undefined,
|
|
140
155
|
identifier: identifier ? [{ value: identifier }] : undefined,
|
|
141
156
|
status,
|
|
157
|
+
type,
|
|
142
158
|
issued: issued || undefined,
|
|
143
159
|
instantiatesUri: instantiatesUri || undefined,
|
|
144
160
|
applies: {
|
|
@@ -38,6 +38,8 @@ 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
|
+
/** True only for an RFC 9278 SHA-256 JWK thumbprint URI. */
|
|
42
|
+
export declare function isJwkThumbprintSha256Urn(value: unknown): value is string;
|
|
41
43
|
/**
|
|
42
44
|
* Returns a public JWK whose `kid` is derived exclusively from its public key
|
|
43
45
|
* material. Caller-provided aliases are deliberately replaced so DID methods,
|
|
@@ -55,6 +55,14 @@ export function computeRfc7638JwkThumbprint(jwk) {
|
|
|
55
55
|
export function toJwkThumbprintSha256Urn(jwk) {
|
|
56
56
|
return `${UrnPrefixes.JwkThumbprintSha256KeyId}${computeRfc7638JwkThumbprint(jwk)}`;
|
|
57
57
|
}
|
|
58
|
+
/** True only for an RFC 9278 SHA-256 JWK thumbprint URI. */
|
|
59
|
+
export function isJwkThumbprintSha256Urn(value) {
|
|
60
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
61
|
+
if (!normalized.startsWith(UrnPrefixes.JwkThumbprintSha256KeyId))
|
|
62
|
+
return false;
|
|
63
|
+
const thumbprint = normalized.slice(UrnPrefixes.JwkThumbprintSha256KeyId.length);
|
|
64
|
+
return /^[A-Za-z0-9_-]{43}$/.test(thumbprint);
|
|
65
|
+
}
|
|
58
66
|
/**
|
|
59
67
|
* Returns a public JWK whose `kid` is derived exclusively from its public key
|
|
60
68
|
* material. Caller-provided aliases are deliberately replaced so DID methods,
|
|
@@ -64,19 +64,27 @@ export declare function readLegalRepresentativeBindingFromResponseBody(responseB
|
|
|
64
64
|
* and legal-representative credential pair.
|
|
65
65
|
*/
|
|
66
66
|
export declare function readOrganizationControllerCredentialsFromResponseBody(responseBody: unknown): LegalOrganizationVerificationCredential[];
|
|
67
|
+
/** Canonical name for reading ICA-issued service-controller credentials. */
|
|
68
|
+
export declare const readServiceControllerCredentialsFromResponseBody: typeof readOrganizationControllerCredentialsFromResponseBody;
|
|
67
69
|
/**
|
|
68
70
|
* Returns one organization-controller service credential in an ICA or
|
|
69
71
|
* projected GW verification response. Pass a stable actor `sameAs` to select
|
|
70
72
|
* one controller independently; otherwise the first controller is returned.
|
|
71
73
|
*/
|
|
72
74
|
export declare function readOrganizationControllerCredentialFromResponseBody(responseBody: unknown, controllerSameAs?: string): LegalOrganizationVerificationCredential | undefined;
|
|
75
|
+
/** Canonical name for selecting one ICA-issued service-controller credential. */
|
|
76
|
+
export declare const readServiceControllerCredentialFromResponseBody: typeof readOrganizationControllerCredentialFromResponseBody;
|
|
73
77
|
/**
|
|
74
78
|
* Reads `credentialSubject.owner.sameAs` from the first
|
|
75
79
|
* organization-controller service credential when present.
|
|
76
80
|
*/
|
|
77
81
|
export declare function readOrganizationControllerSameAsFromResponseBody(responseBody: unknown): string | undefined;
|
|
82
|
+
/** Canonical name for reading a service controller's stable actor identifier. */
|
|
83
|
+
export declare const readServiceControllerSameAsFromResponseBody: typeof readOrganizationControllerSameAsFromResponseBody;
|
|
78
84
|
/**
|
|
79
85
|
* Reads `credentialSubject.owner.hasCredential.material` from the first
|
|
80
86
|
* organization-controller service credential when present.
|
|
81
87
|
*/
|
|
82
88
|
export declare function readOrganizationControllerBindingFromResponseBody(responseBody: unknown): string | undefined;
|
|
89
|
+
/** Canonical name for reading a service controller's actor-key binding. */
|
|
90
|
+
export declare const readServiceControllerBindingFromResponseBody: typeof readOrganizationControllerBindingFromResponseBody;
|
|
@@ -152,10 +152,13 @@ export function readLegalRepresentativeBindingFromResponseBody(responseBody) {
|
|
|
152
152
|
*/
|
|
153
153
|
export function readOrganizationControllerCredentialsFromResponseBody(responseBody) {
|
|
154
154
|
return getLegalOrganizationVerificationEntriesFromResponseBody(responseBody)
|
|
155
|
-
.filter((entry) => hasCredentialType(entry, '
|
|
155
|
+
.filter((entry) => hasCredentialType(entry, 'ServiceControllerCredential')
|
|
156
|
+
|| hasCredentialType(entry, 'OrganizationControllerCredential'))
|
|
156
157
|
.map((entry) => asObject(asObject(entry)?.resource) || asObject(entry))
|
|
157
158
|
.filter((entry) => Boolean(entry));
|
|
158
159
|
}
|
|
160
|
+
/** Canonical name for reading ICA-issued service-controller credentials. */
|
|
161
|
+
export const readServiceControllerCredentialsFromResponseBody = readOrganizationControllerCredentialsFromResponseBody;
|
|
159
162
|
/**
|
|
160
163
|
* Returns one organization-controller service credential in an ICA or
|
|
161
164
|
* projected GW verification response. Pass a stable actor `sameAs` to select
|
|
@@ -168,6 +171,8 @@ export function readOrganizationControllerCredentialFromResponseBody(responseBod
|
|
|
168
171
|
? credentials.find((credential) => extractOrganizationControllerSameAs(credential) === expectedSameAs)
|
|
169
172
|
: credentials[0];
|
|
170
173
|
}
|
|
174
|
+
/** Canonical name for selecting one ICA-issued service-controller credential. */
|
|
175
|
+
export const readServiceControllerCredentialFromResponseBody = readOrganizationControllerCredentialFromResponseBody;
|
|
171
176
|
/**
|
|
172
177
|
* Reads `credentialSubject.owner.sameAs` from the first
|
|
173
178
|
* organization-controller service credential when present.
|
|
@@ -175,6 +180,8 @@ export function readOrganizationControllerCredentialFromResponseBody(responseBod
|
|
|
175
180
|
export function readOrganizationControllerSameAsFromResponseBody(responseBody) {
|
|
176
181
|
return extractOrganizationControllerSameAs(readOrganizationControllerCredentialFromResponseBody(responseBody));
|
|
177
182
|
}
|
|
183
|
+
/** Canonical name for reading a service controller's stable actor identifier. */
|
|
184
|
+
export const readServiceControllerSameAsFromResponseBody = readOrganizationControllerSameAsFromResponseBody;
|
|
178
185
|
/**
|
|
179
186
|
* Reads `credentialSubject.owner.hasCredential.material` from the first
|
|
180
187
|
* organization-controller service credential when present.
|
|
@@ -182,3 +189,5 @@ export function readOrganizationControllerSameAsFromResponseBody(responseBody) {
|
|
|
182
189
|
export function readOrganizationControllerBindingFromResponseBody(responseBody) {
|
|
183
190
|
return extractOrganizationControllerBinding(readOrganizationControllerCredentialFromResponseBody(responseBody));
|
|
184
191
|
}
|
|
192
|
+
/** Canonical name for reading a service controller's actor-key binding. */
|
|
193
|
+
export const readServiceControllerBindingFromResponseBody = readOrganizationControllerBindingFromResponseBody;
|
|
@@ -84,11 +84,16 @@ export type LegalOrganizationVerificationTransactionInput = Readonly<{
|
|
|
84
84
|
}>;
|
|
85
85
|
export type LegalOrganizationVerificationTransactionEntry = Readonly<{
|
|
86
86
|
type?: string;
|
|
87
|
+
/** @deprecated Read-only compatibility with payloads emitted before 2.5.x. */
|
|
87
88
|
meta?: {
|
|
88
89
|
claims?: ClaimsRecord;
|
|
89
90
|
[key: string]: unknown;
|
|
90
91
|
};
|
|
91
92
|
resource?: {
|
|
93
|
+
meta?: {
|
|
94
|
+
claims?: ClaimsRecord;
|
|
95
|
+
[key: string]: unknown;
|
|
96
|
+
};
|
|
92
97
|
controller?: LegalOrganizationVerificationTransactionController;
|
|
93
98
|
organization?: LegalOrganizationVerificationTransactionOrganization;
|
|
94
99
|
/** @deprecated Legacy demo/OTP compatibility input. */
|
|
@@ -106,7 +111,7 @@ export type LegalOrganizationVerificationTransactionEntry = Readonly<{
|
|
|
106
111
|
* verification transactions.
|
|
107
112
|
*
|
|
108
113
|
* Contract notes:
|
|
109
|
-
* - business claims
|
|
114
|
+
* - business claims live in `resource.meta.claims`
|
|
110
115
|
* - controller binding material remains in `resource.controller.*`
|
|
111
116
|
* - organization signing material remains in `resource.organization.*`
|
|
112
117
|
* - PDF evidence or URL attachments stay at the DIDComm-message level
|
|
@@ -31,7 +31,7 @@ function asRecord(value) {
|
|
|
31
31
|
* verification transactions.
|
|
32
32
|
*
|
|
33
33
|
* Contract notes:
|
|
34
|
-
* - business claims
|
|
34
|
+
* - business claims live in `resource.meta.claims`
|
|
35
35
|
* - controller binding material remains in `resource.controller.*`
|
|
36
36
|
* - organization signing material remains in `resource.organization.*`
|
|
37
37
|
* - PDF evidence or URL attachments stay at the DIDComm-message level
|
|
@@ -49,10 +49,10 @@ export function buildLegalOrganizationVerificationTransactionBundle(input) {
|
|
|
49
49
|
total: 1,
|
|
50
50
|
data: [{
|
|
51
51
|
type: LegalOrganizationVerificationTransactionEntryTypes.Request,
|
|
52
|
-
meta: {
|
|
53
|
-
claims: input.claims,
|
|
54
|
-
},
|
|
55
52
|
resource: {
|
|
53
|
+
meta: {
|
|
54
|
+
claims: input.claims,
|
|
55
|
+
},
|
|
56
56
|
controller: input.controller,
|
|
57
57
|
...(input.organization ? { organization: input.organization } : {}),
|
|
58
58
|
...(input.legalRepresentativePayload
|
package/dist/utils/license.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeviceAppTypes, DeviceUserClasses } from '../constants/device.js';
|
|
1
|
+
import { DeviceAppTypes, DeviceBindingStatuses, DeviceUserClasses } from '../constants/device.js';
|
|
2
2
|
import { ClaimsIndividualProductSchemaorg, ClaimsOfferSchemaorg, ClaimsPersonSchemaorg, } from '../constants/schemaorg.js';
|
|
3
3
|
/** Default simultaneous installation allowance for one professional/member seat. */
|
|
4
4
|
export const DEFAULT_LICENSE_DEVICE_ALLOWANCE = 2;
|
|
@@ -13,7 +13,7 @@ export function resolveLicenseDeviceAllowance(license) {
|
|
|
13
13
|
*/
|
|
14
14
|
export function listActiveLicenseDeviceBindings(license) {
|
|
15
15
|
if (Array.isArray(license.deviceBindings)) {
|
|
16
|
-
return license.deviceBindings.filter((binding) => binding.status ===
|
|
16
|
+
return license.deviceBindings.filter((binding) => binding.status === DeviceBindingStatuses.Active);
|
|
17
17
|
}
|
|
18
18
|
const clientId = String(license.deviceId || '').trim();
|
|
19
19
|
if (!clientId)
|
|
@@ -22,7 +22,7 @@ export function listActiveLicenseDeviceBindings(license) {
|
|
|
22
22
|
return [{
|
|
23
23
|
clientId,
|
|
24
24
|
clientInstanceId: deviceInfo.clientInstanceId || clientId,
|
|
25
|
-
status:
|
|
25
|
+
status: DeviceBindingStatuses.Active,
|
|
26
26
|
deviceInfo,
|
|
27
27
|
activatedAt: Number(license.activatedAt || 0),
|
|
28
28
|
}];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EmployeeDeviceRevocationTarget, OrganizationEmployeeLifecycleRecord } from '../models/organization-employee-lifecycle';
|
|
2
|
+
/** Builds the exact identity/auth revoke request body from a typed target. */
|
|
3
|
+
export declare function buildEmployeeDeviceRevocationBody(target: EmployeeDeviceRevocationTarget): Readonly<Record<string, string>>;
|
|
4
|
+
/** Reads an employee activation credential from canonical and legacy GW envelopes. */
|
|
5
|
+
export declare function readEmployeeActivationCode(value: unknown): string;
|
|
6
|
+
/** Extracts GW search rows regardless of async job envelope depth. */
|
|
7
|
+
export declare function extractGwSearchResources(value: unknown): ReadonlyArray<Record<string, unknown>>;
|
|
8
|
+
/** Combines employee directory and license search results into one typed view. */
|
|
9
|
+
export declare function projectOrganizationEmployeeLifecycle(input: Readonly<{
|
|
10
|
+
employeeResponse: unknown;
|
|
11
|
+
licenseResponse: unknown;
|
|
12
|
+
}>): OrganizationEmployeeLifecycleRecord[];
|