gdc-common-utils-ts 2.0.16 → 2.0.18
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/dist/constants/verifiable-credentials.d.ts +7 -0
- package/dist/constants/verifiable-credentials.js +7 -0
- package/dist/examples/contract-examples.d.ts +1 -0
- package/dist/examples/contract-examples.js +1 -0
- package/dist/examples/index.d.ts +1 -0
- package/dist/examples/index.js +1 -0
- package/dist/examples/inter-tenant-access-contract.d.ts +124 -0
- package/dist/examples/inter-tenant-access-contract.js +134 -0
- package/dist/examples/shared.d.ts +5 -0
- package/dist/examples/shared.js +5 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/inter-tenant-access-contract.d.ts +105 -0
- package/dist/models/inter-tenant-access-contract.js +78 -0
- package/dist/utils/bundle-reader.d.ts +19 -0
- package/dist/utils/bundle-reader.js +43 -0
- package/dist/utils/evidence-blockchain-references.d.ts +2 -0
- package/dist/utils/evidence-blockchain-references.js +4 -0
- package/dist/utils/gw-core-commercial-contract.d.ts +41 -0
- package/dist/utils/gw-core-commercial-contract.js +71 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/inter-tenant-access-contract.d.ts +44 -0
- package/dist/utils/inter-tenant-access-contract.js +358 -0
- package/dist/utils/legal-organization-verification-result.d.ts +37 -0
- package/dist/utils/legal-organization-verification-result.js +106 -0
- package/dist/utils/organization-authorization-urn.d.ts +43 -0
- package/dist/utils/organization-authorization-urn.js +87 -0
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type LegalOrganizationVerificationCredential = Record<string, unknown>;
|
|
2
|
+
export type LegalOrganizationVerificationCredentialPair = Readonly<{
|
|
3
|
+
verificationEntries: readonly unknown[];
|
|
4
|
+
organizationCredential: LegalOrganizationVerificationCredential;
|
|
5
|
+
legalRepresentativeCredential: LegalOrganizationVerificationCredential;
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the ICA verification entries currently projected by GW host
|
|
9
|
+
* legal-organization `_transaction`.
|
|
10
|
+
*
|
|
11
|
+
* Supported shapes:
|
|
12
|
+
* - direct `vc[]` projection on the first response entry
|
|
13
|
+
* - nested `resource.icaResponse.body.data[]`
|
|
14
|
+
* - direct ICA `_verify-response` bodies reused in tests/docs
|
|
15
|
+
*/
|
|
16
|
+
export declare function getLegalOrganizationVerificationEntriesFromResponseBody(responseBody: unknown): unknown[];
|
|
17
|
+
/**
|
|
18
|
+
* Reads the organization and legal-representative credentials returned by the
|
|
19
|
+
* legal-organization verification flow.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody: unknown): LegalOrganizationVerificationCredentialPair;
|
|
22
|
+
/**
|
|
23
|
+
* Reads the canonical organization tax id from the verification credential
|
|
24
|
+
* pair and enforces agreement between organization and representative VC when
|
|
25
|
+
* both values are present.
|
|
26
|
+
*/
|
|
27
|
+
export declare function readLegalOrganizationVerificationTaxIdFromResponseBody(responseBody: unknown): string;
|
|
28
|
+
/**
|
|
29
|
+
* Reads `credentialSubject.sameAs` from the legal-representative credential
|
|
30
|
+
* when present.
|
|
31
|
+
*/
|
|
32
|
+
export declare function readLegalRepresentativeSameAsFromResponseBody(responseBody: unknown): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Reads `credentialSubject.hasCredential.material` continuity data from the
|
|
35
|
+
* legal-representative credential when present.
|
|
36
|
+
*/
|
|
37
|
+
export declare function readLegalRepresentativeBindingFromResponseBody(responseBody: unknown): string | undefined;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { extractCredentialSubject, extractOrganizationTaxId, extractRepresentativeCredentialBinding, extractRepresentativeMemberOfTaxId, } from './activation-policy.js';
|
|
2
|
+
function asObject(value) {
|
|
3
|
+
if (!value || typeof value !== 'object')
|
|
4
|
+
return undefined;
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
function asArray(value) {
|
|
8
|
+
return Array.isArray(value) ? value : [];
|
|
9
|
+
}
|
|
10
|
+
function findCredentialResource(entries, expectedTypeFragment, fallbackIndex) {
|
|
11
|
+
const byType = entries.find((entry) => {
|
|
12
|
+
const candidate = asObject(entry);
|
|
13
|
+
const typeValue = candidate?.type;
|
|
14
|
+
const tokens = Array.isArray(typeValue)
|
|
15
|
+
? typeValue.map((token) => String(token || ''))
|
|
16
|
+
: [String(typeValue || '')];
|
|
17
|
+
return tokens.some((token) => token.includes(expectedTypeFragment));
|
|
18
|
+
});
|
|
19
|
+
const selected = asObject(byType) || asObject(entries[fallbackIndex]);
|
|
20
|
+
const resource = asObject(selected?.resource) || selected;
|
|
21
|
+
if (!resource) {
|
|
22
|
+
throw new Error(`Missing '${expectedTypeFragment}' verification credential in legal-organization verification response.`);
|
|
23
|
+
}
|
|
24
|
+
return resource;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns the ICA verification entries currently projected by GW host
|
|
28
|
+
* legal-organization `_transaction`.
|
|
29
|
+
*
|
|
30
|
+
* Supported shapes:
|
|
31
|
+
* - direct `vc[]` projection on the first response entry
|
|
32
|
+
* - nested `resource.icaResponse.body.data[]`
|
|
33
|
+
* - direct ICA `_verify-response` bodies reused in tests/docs
|
|
34
|
+
*/
|
|
35
|
+
export function getLegalOrganizationVerificationEntriesFromResponseBody(responseBody) {
|
|
36
|
+
const root = asObject(responseBody) || {};
|
|
37
|
+
const topLevelEntries = asArray(root.data);
|
|
38
|
+
const bodyEntries = asArray(asObject(root.body)?.data);
|
|
39
|
+
const firstEntry = asObject(bodyEntries[0]) || asObject(topLevelEntries[0]) || {};
|
|
40
|
+
const projectedCredentials = asArray(firstEntry.vc);
|
|
41
|
+
if (projectedCredentials.length >= 2) {
|
|
42
|
+
return projectedCredentials;
|
|
43
|
+
}
|
|
44
|
+
const nestedIcaResponse = asObject(asObject(firstEntry.resource)?.icaResponse) || {};
|
|
45
|
+
const nestedBodyEntries = asArray(asObject(nestedIcaResponse.body)?.data);
|
|
46
|
+
if (nestedBodyEntries.length >= 2) {
|
|
47
|
+
return nestedBodyEntries;
|
|
48
|
+
}
|
|
49
|
+
const nestedTopLevelEntries = asArray(nestedIcaResponse.data);
|
|
50
|
+
if (nestedTopLevelEntries.length >= 2) {
|
|
51
|
+
return nestedTopLevelEntries;
|
|
52
|
+
}
|
|
53
|
+
if (bodyEntries.length >= 2) {
|
|
54
|
+
return bodyEntries;
|
|
55
|
+
}
|
|
56
|
+
if (topLevelEntries.length >= 2) {
|
|
57
|
+
return topLevelEntries;
|
|
58
|
+
}
|
|
59
|
+
throw new Error('Legal-organization verification response is missing ICA verification credential entries.');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reads the organization and legal-representative credentials returned by the
|
|
63
|
+
* legal-organization verification flow.
|
|
64
|
+
*/
|
|
65
|
+
export function readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody) {
|
|
66
|
+
const verificationEntries = getLegalOrganizationVerificationEntriesFromResponseBody(responseBody);
|
|
67
|
+
return {
|
|
68
|
+
verificationEntries,
|
|
69
|
+
organizationCredential: findCredentialResource(verificationEntries, 'Organization', 0),
|
|
70
|
+
legalRepresentativeCredential: findCredentialResource(verificationEntries, 'LegalRepresentative', 1),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Reads the canonical organization tax id from the verification credential
|
|
75
|
+
* pair and enforces agreement between organization and representative VC when
|
|
76
|
+
* both values are present.
|
|
77
|
+
*/
|
|
78
|
+
export function readLegalOrganizationVerificationTaxIdFromResponseBody(responseBody) {
|
|
79
|
+
const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
|
|
80
|
+
const organizationTaxId = extractOrganizationTaxId(pair.organizationCredential);
|
|
81
|
+
const representativeTaxId = extractRepresentativeMemberOfTaxId(pair.legalRepresentativeCredential);
|
|
82
|
+
const resolvedTaxId = organizationTaxId || representativeTaxId;
|
|
83
|
+
if (!resolvedTaxId) {
|
|
84
|
+
throw new Error('Legal-organization verification response is missing organization tax id in both organization and representative credentials.');
|
|
85
|
+
}
|
|
86
|
+
if (organizationTaxId && representativeTaxId && organizationTaxId !== representativeTaxId) {
|
|
87
|
+
throw new Error('Legal-organization verification response contains mismatched organization tax ids between organization and representative credentials.');
|
|
88
|
+
}
|
|
89
|
+
return resolvedTaxId;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Reads `credentialSubject.sameAs` from the legal-representative credential
|
|
93
|
+
* when present.
|
|
94
|
+
*/
|
|
95
|
+
export function readLegalRepresentativeSameAsFromResponseBody(responseBody) {
|
|
96
|
+
const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
|
|
97
|
+
return String(extractCredentialSubject(pair.legalRepresentativeCredential)?.sameAs || '').trim() || undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reads `credentialSubject.hasCredential.material` continuity data from the
|
|
101
|
+
* legal-representative credential when present.
|
|
102
|
+
*/
|
|
103
|
+
export function readLegalRepresentativeBindingFromResponseBody(responseBody) {
|
|
104
|
+
const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
|
|
105
|
+
return extractRepresentativeCredentialBinding(pair.legalRepresentativeCredential);
|
|
106
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ClaimsRecord } from '../models/resource-document';
|
|
2
|
+
export type OrganizationAuthorizationUrnInput = Readonly<{
|
|
3
|
+
identifierType: string;
|
|
4
|
+
identifierValue: string;
|
|
5
|
+
}>;
|
|
6
|
+
export type MemberAuthorizationUrnInput = Readonly<{
|
|
7
|
+
organizationUrn?: string;
|
|
8
|
+
identifierType?: string;
|
|
9
|
+
identifierValue?: string;
|
|
10
|
+
memberId: string;
|
|
11
|
+
/** Optional compatibility input. Role must be persisted separately, not inside the canonical member URN. */
|
|
12
|
+
roleCode?: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Canonical organization authorization identifier used by ledger, consent-like
|
|
16
|
+
* rules, and inter-tenant authorization persistence.
|
|
17
|
+
*
|
|
18
|
+
* Format:
|
|
19
|
+
* - `urn:org:<identifierType-lowercase>:<identifierValue-as-canonical-input>`
|
|
20
|
+
*
|
|
21
|
+
* Examples:
|
|
22
|
+
* - `urn:org:tax:VATES-B12345678`
|
|
23
|
+
* - `urn:org:tax:acme-id`
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildOrganizationAuthorizationUrn(input: OrganizationAuthorizationUrnInput): string;
|
|
26
|
+
/**
|
|
27
|
+
* Accepts either the legacy `TYPE|VALUE` input or an already-canonical
|
|
28
|
+
* `urn:org:...` identifier and always returns the canonical URN form.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeOrganizationAuthorizationUrn(input: string): string;
|
|
31
|
+
export declare function buildOrganizationAuthorizationUrnFromClaims(claims?: ClaimsRecord): string;
|
|
32
|
+
/**
|
|
33
|
+
* Canonical member authorization identifier rooted in one canonical
|
|
34
|
+
* `urn:org:...`.
|
|
35
|
+
*
|
|
36
|
+
* Format:
|
|
37
|
+
* - `urn:org:<type>:<value>:member:<memberId>`
|
|
38
|
+
*
|
|
39
|
+
* Important rule:
|
|
40
|
+
* - role must be stored as a separate claim, not inside the canonical member
|
|
41
|
+
* identifier
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildMemberAuthorizationUrn(input: MemberAuthorizationUrnInput): string;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { ClaimsOrganizationSchemaorg } from '../constants/schemaorg.js';
|
|
3
|
+
const ORGANIZATION_URN_PREFIX = 'urn:org:';
|
|
4
|
+
function normalizeTypeSegment(identifierType) {
|
|
5
|
+
return String(identifierType || '').trim().toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
function normalizeValueSegment(identifierValue) {
|
|
8
|
+
return String(identifierValue || '').trim();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Canonical organization authorization identifier used by ledger, consent-like
|
|
12
|
+
* rules, and inter-tenant authorization persistence.
|
|
13
|
+
*
|
|
14
|
+
* Format:
|
|
15
|
+
* - `urn:org:<identifierType-lowercase>:<identifierValue-as-canonical-input>`
|
|
16
|
+
*
|
|
17
|
+
* Examples:
|
|
18
|
+
* - `urn:org:tax:VATES-B12345678`
|
|
19
|
+
* - `urn:org:tax:acme-id`
|
|
20
|
+
*/
|
|
21
|
+
export function buildOrganizationAuthorizationUrn(input) {
|
|
22
|
+
const identifierType = normalizeTypeSegment(input.identifierType);
|
|
23
|
+
const identifierValue = normalizeValueSegment(input.identifierValue);
|
|
24
|
+
if (!identifierType || !identifierValue) {
|
|
25
|
+
throw new Error('Organization authorization URN requires identifierType and identifierValue.');
|
|
26
|
+
}
|
|
27
|
+
return `${ORGANIZATION_URN_PREFIX}${identifierType}:${identifierValue}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Accepts either the legacy `TYPE|VALUE` input or an already-canonical
|
|
31
|
+
* `urn:org:...` identifier and always returns the canonical URN form.
|
|
32
|
+
*/
|
|
33
|
+
export function normalizeOrganizationAuthorizationUrn(input) {
|
|
34
|
+
const normalized = String(input || '').trim();
|
|
35
|
+
if (!normalized) {
|
|
36
|
+
throw new Error('Organization authorization identifier cannot be empty.');
|
|
37
|
+
}
|
|
38
|
+
if (normalized.toLowerCase().startsWith(ORGANIZATION_URN_PREFIX)) {
|
|
39
|
+
const parts = normalized.split(':');
|
|
40
|
+
const identifierType = String(parts[2] || '').trim();
|
|
41
|
+
const value = parts.slice(3).join(':').trim();
|
|
42
|
+
return buildOrganizationAuthorizationUrn({
|
|
43
|
+
identifierType,
|
|
44
|
+
identifierValue: value,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const legacyMatch = normalized.match(/^([^|:]+)\|(.+)$/);
|
|
48
|
+
if (legacyMatch) {
|
|
49
|
+
return buildOrganizationAuthorizationUrn({
|
|
50
|
+
identifierType: legacyMatch[1],
|
|
51
|
+
identifierValue: legacyMatch[2],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`Unsupported organization authorization identifier format: ${normalized}`);
|
|
55
|
+
}
|
|
56
|
+
export function buildOrganizationAuthorizationUrnFromClaims(claims) {
|
|
57
|
+
const identifierType = String(claims?.[ClaimsOrganizationSchemaorg.identifierType] || '').trim();
|
|
58
|
+
const identifierValue = String(claims?.[ClaimsOrganizationSchemaorg.identifierValue] || '').trim();
|
|
59
|
+
return buildOrganizationAuthorizationUrn({
|
|
60
|
+
identifierType,
|
|
61
|
+
identifierValue,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Canonical member authorization identifier rooted in one canonical
|
|
66
|
+
* `urn:org:...`.
|
|
67
|
+
*
|
|
68
|
+
* Format:
|
|
69
|
+
* - `urn:org:<type>:<value>:member:<memberId>`
|
|
70
|
+
*
|
|
71
|
+
* Important rule:
|
|
72
|
+
* - role must be stored as a separate claim, not inside the canonical member
|
|
73
|
+
* identifier
|
|
74
|
+
*/
|
|
75
|
+
export function buildMemberAuthorizationUrn(input) {
|
|
76
|
+
const organizationUrn = input.organizationUrn
|
|
77
|
+
? normalizeOrganizationAuthorizationUrn(input.organizationUrn)
|
|
78
|
+
: buildOrganizationAuthorizationUrn({
|
|
79
|
+
identifierType: String(input.identifierType || '').trim(),
|
|
80
|
+
identifierValue: String(input.identifierValue || '').trim(),
|
|
81
|
+
});
|
|
82
|
+
const memberId = String(input.memberId || '').trim();
|
|
83
|
+
if (!memberId) {
|
|
84
|
+
throw new Error('Member authorization URN requires memberId.');
|
|
85
|
+
}
|
|
86
|
+
return `${organizationUrn}:member:${memberId}`;
|
|
87
|
+
}
|