vet-data-utils-ts 0.4.1 → 0.4.2
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 +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/organization-application.d.ts +44 -0
- package/dist/organization-application.js +105 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -8,6 +8,15 @@ Current surfaces cover the canonical animal-card DID, veterinary summary
|
|
|
8
8
|
sections, animal-only emergency data, pseudonymous DigitalTwin search input and
|
|
9
9
|
veterinary assistant intents.
|
|
10
10
|
|
|
11
|
+
`vet-data-utils-ts/organization-application` is the product-neutral application
|
|
12
|
+
value used by UHC UNID, VetChain and SOSChain adapters. The host supplies the
|
|
13
|
+
allowed sector list and translated labels. The value contains one official
|
|
14
|
+
identifier (`TAX`, `EIN` or `BN`), ISO country, optional matching ISO
|
|
15
|
+
subdivision, optional official licence, legal representative, technical
|
|
16
|
+
controller and six independent index participation roles. It rejects a second
|
|
17
|
+
`taxId` and every PIN field: profile protection happens immediately after
|
|
18
|
+
login, before any application screen.
|
|
19
|
+
|
|
11
20
|
The financial surface defines provider-neutral flat claims for FHIR R5
|
|
12
21
|
`Account`, `Invoice`, `PaymentNotice` and `PaymentReconciliation`. `Account`
|
|
13
22
|
tracks charges and balances; the responsible party is represented through
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const OrganizationOfficialIdTypes: Readonly<{
|
|
2
|
+
readonly Tax: "TAX";
|
|
3
|
+
readonly EmployerIdentificationNumber: "EIN";
|
|
4
|
+
readonly BusinessNumber: "BN";
|
|
5
|
+
}>;
|
|
6
|
+
export declare const OrganizationParticipationRoles: Readonly<{
|
|
7
|
+
readonly IndividualIndexServiceProvider: "individual-index-service-provider";
|
|
8
|
+
readonly IndividualIndexDataProvider: "individual-index-data-provider";
|
|
9
|
+
readonly IndividualIndexDataConsumer: "individual-index-data-consumer";
|
|
10
|
+
readonly DigitalTwinIndexServiceProvider: "digital-twin-index-service-provider";
|
|
11
|
+
readonly DigitalTwinDataProvider: "digital-twin-data-provider";
|
|
12
|
+
readonly DigitalTwinDataConsumer: "digital-twin-data-consumer";
|
|
13
|
+
}>;
|
|
14
|
+
export type OrganizationOfficialIdType = typeof OrganizationOfficialIdTypes[keyof typeof OrganizationOfficialIdTypes];
|
|
15
|
+
export type OrganizationParticipationRole = typeof OrganizationParticipationRoles[keyof typeof OrganizationParticipationRoles];
|
|
16
|
+
export type ReusableOrganizationApplication = Readonly<{
|
|
17
|
+
sector: string;
|
|
18
|
+
officialId: Readonly<{
|
|
19
|
+
type: OrganizationOfficialIdType;
|
|
20
|
+
value: string;
|
|
21
|
+
}>;
|
|
22
|
+
countryCode: string;
|
|
23
|
+
regionalId: boolean;
|
|
24
|
+
subdivisionCode?: string;
|
|
25
|
+
officialLicense?: string;
|
|
26
|
+
legalRepresentative: Readonly<{
|
|
27
|
+
name: string;
|
|
28
|
+
email: string;
|
|
29
|
+
}>;
|
|
30
|
+
technicalController: Readonly<{
|
|
31
|
+
email: string;
|
|
32
|
+
sameAsLegalRepresentative: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
participationRoles: readonly OrganizationParticipationRole[];
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Validates only reusable organization-application business data.
|
|
38
|
+
*
|
|
39
|
+
* Product adapters supply the sector allowlist and translated labels. Login,
|
|
40
|
+
* PIN/passkey protection, PDF rendering, delivery, activation-code exchange,
|
|
41
|
+
* DCR, wallet keys and gateway routing are deliberately outside this value
|
|
42
|
+
* object and remain inside the BFF/high-level Node runtime.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseReusableOrganizationApplication(input: unknown): ReusableOrganizationApplication;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { isIso3166CountryCode, isIso3166SubdivisionForCountry } from './iso-jurisdictions.js';
|
|
2
|
+
export const OrganizationOfficialIdTypes = Object.freeze({
|
|
3
|
+
Tax: 'TAX',
|
|
4
|
+
EmployerIdentificationNumber: 'EIN',
|
|
5
|
+
BusinessNumber: 'BN',
|
|
6
|
+
});
|
|
7
|
+
export const OrganizationParticipationRoles = Object.freeze({
|
|
8
|
+
IndividualIndexServiceProvider: 'individual-index-service-provider',
|
|
9
|
+
IndividualIndexDataProvider: 'individual-index-data-provider',
|
|
10
|
+
IndividualIndexDataConsumer: 'individual-index-data-consumer',
|
|
11
|
+
DigitalTwinIndexServiceProvider: 'digital-twin-index-service-provider',
|
|
12
|
+
DigitalTwinDataProvider: 'digital-twin-data-provider',
|
|
13
|
+
DigitalTwinDataConsumer: 'digital-twin-data-consumer',
|
|
14
|
+
});
|
|
15
|
+
const officialIdTypes = new Set(Object.values(OrganizationOfficialIdTypes));
|
|
16
|
+
const participationRoles = new Set(Object.values(OrganizationParticipationRoles));
|
|
17
|
+
/**
|
|
18
|
+
* Validates only reusable organization-application business data.
|
|
19
|
+
*
|
|
20
|
+
* Product adapters supply the sector allowlist and translated labels. Login,
|
|
21
|
+
* PIN/passkey protection, PDF rendering, delivery, activation-code exchange,
|
|
22
|
+
* DCR, wallet keys and gateway routing are deliberately outside this value
|
|
23
|
+
* object and remain inside the BFF/high-level Node runtime.
|
|
24
|
+
*/
|
|
25
|
+
export function parseReusableOrganizationApplication(input) {
|
|
26
|
+
const value = record(input, 'organization_application_invalid');
|
|
27
|
+
forbid(value, ['taxId', 'profilePin', 'newProfilePin', 'repeatProfilePin']);
|
|
28
|
+
const allowedSectors = strings(value.allowedSectors);
|
|
29
|
+
const sector = required(value.sector, 'organization_sector_required');
|
|
30
|
+
if (!allowedSectors.includes(sector))
|
|
31
|
+
throw new TypeError('organization_sector_not_allowed');
|
|
32
|
+
const officialId = record(value.officialId, 'organization_official_id_required');
|
|
33
|
+
const officialIdType = required(officialId.type, 'organization_official_id_type_required');
|
|
34
|
+
if (!officialIdTypes.has(officialIdType))
|
|
35
|
+
throw new TypeError('organization_official_id_type_invalid');
|
|
36
|
+
const countryCode = required(value.countryCode, 'organization_country_required').toUpperCase();
|
|
37
|
+
if (!isIso3166CountryCode(countryCode))
|
|
38
|
+
throw new TypeError('organization_country_invalid');
|
|
39
|
+
const regionalId = value.regionalId === true;
|
|
40
|
+
const subdivisionCode = optional(value.subdivisionCode)?.toUpperCase();
|
|
41
|
+
if (regionalId && (!subdivisionCode || !isIso3166SubdivisionForCountry(subdivisionCode, countryCode))) {
|
|
42
|
+
throw new TypeError('organization_subdivision_invalid');
|
|
43
|
+
}
|
|
44
|
+
if (!regionalId && subdivisionCode)
|
|
45
|
+
throw new TypeError('organization_subdivision_without_regional_id');
|
|
46
|
+
const legalRepresentative = record(value.legalRepresentative, 'organization_legal_representative_required');
|
|
47
|
+
const legalEmail = email(legalRepresentative.email, 'organization_legal_representative_email_required');
|
|
48
|
+
const technicalController = record(value.technicalController, 'organization_technical_controller_required');
|
|
49
|
+
const sameAsLegalRepresentative = technicalController.sameAsLegalRepresentative === true;
|
|
50
|
+
const technicalEmail = sameAsLegalRepresentative
|
|
51
|
+
? legalEmail
|
|
52
|
+
: email(technicalController.email, 'organization_technical_controller_email_required');
|
|
53
|
+
const selectedRoles = strings(value.participationRoles);
|
|
54
|
+
if (selectedRoles.some(role => !participationRoles.has(role))) {
|
|
55
|
+
throw new TypeError('organization_participation_role_invalid');
|
|
56
|
+
}
|
|
57
|
+
return Object.freeze({
|
|
58
|
+
sector,
|
|
59
|
+
officialId: Object.freeze({
|
|
60
|
+
type: officialIdType,
|
|
61
|
+
value: required(officialId.value, 'organization_official_id_value_required'),
|
|
62
|
+
}),
|
|
63
|
+
countryCode,
|
|
64
|
+
regionalId,
|
|
65
|
+
...(subdivisionCode ? { subdivisionCode } : {}),
|
|
66
|
+
...(optional(value.officialLicense) ? { officialLicense: optional(value.officialLicense) } : {}),
|
|
67
|
+
legalRepresentative: Object.freeze({
|
|
68
|
+
name: required(legalRepresentative.name, 'organization_legal_representative_name_required'),
|
|
69
|
+
email: legalEmail,
|
|
70
|
+
}),
|
|
71
|
+
technicalController: Object.freeze({ email: technicalEmail, sameAsLegalRepresentative }),
|
|
72
|
+
participationRoles: Object.freeze([...new Set(selectedRoles)]),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function record(value, error) {
|
|
76
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
77
|
+
throw new TypeError(error);
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
function strings(value) {
|
|
81
|
+
return Array.isArray(value) ? value.map(item => String(item).trim()).filter(Boolean) : [];
|
|
82
|
+
}
|
|
83
|
+
function required(value, error) {
|
|
84
|
+
const normalized = String(value ?? '').trim();
|
|
85
|
+
if (!normalized)
|
|
86
|
+
throw new TypeError(error);
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
function optional(value) {
|
|
90
|
+
const normalized = String(value ?? '').trim();
|
|
91
|
+
return normalized || undefined;
|
|
92
|
+
}
|
|
93
|
+
function email(value, error) {
|
|
94
|
+
const normalized = required(value, error).toLowerCase();
|
|
95
|
+
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(normalized))
|
|
96
|
+
throw new TypeError(error);
|
|
97
|
+
return normalized;
|
|
98
|
+
}
|
|
99
|
+
function forbid(value, names) {
|
|
100
|
+
for (const name of names) {
|
|
101
|
+
if (Object.prototype.hasOwnProperty.call(value, name)) {
|
|
102
|
+
throw new TypeError(name === 'taxId' ? 'organization_tax_id_forbidden' : 'organization_profile_pin_forbidden');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vet-data-utils-ts",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Browser-safe governed VetChain data contracts",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Connecting Solution & Applications Ltd",
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"types": "./dist/iso-jurisdictions.d.ts",
|
|
33
33
|
"default": "./dist/iso-jurisdictions.js"
|
|
34
34
|
},
|
|
35
|
+
"./organization-application": {
|
|
36
|
+
"types": "./dist/organization-application.d.ts",
|
|
37
|
+
"default": "./dist/organization-application.js"
|
|
38
|
+
},
|
|
35
39
|
"./veterinary-sections": {
|
|
36
40
|
"types": "./dist/veterinary-sections.d.ts",
|
|
37
41
|
"default": "./dist/veterinary-sections.js"
|