vet-sdk-core-ts 0.4.38 → 0.4.39
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
CHANGED
|
@@ -7,6 +7,12 @@ An animal is the first member of its own Individual Organization, so
|
|
|
7
7
|
human that creates it is `Organization.owner`, the controller by default;
|
|
8
8
|
`RESPRSN` must never be copied into the animal member.
|
|
9
9
|
|
|
10
|
+
Name, birth date, exact NCBI species and optional breed are animal
|
|
11
|
+
demographics. Breed remains separate descriptive text. Controller-authored
|
|
12
|
+
demographics remain editable until a veterinarian attests them; attestation
|
|
13
|
+
does not rewrite the original author, and later correction creates a new
|
|
14
|
+
veterinarian-authored version.
|
|
15
|
+
|
|
10
16
|
Use `buildVetChainAnimalDraftClaims(...)` while the name, exact NCBI species or
|
|
11
17
|
public Card is missing. Only a draft for which
|
|
12
18
|
`readVetChainAnimalOnboardingReadiness(...)` returns `ready: true` may be
|
|
@@ -11,6 +11,7 @@ export type VetChainAnimalOnboardingInput = Readonly<{
|
|
|
11
11
|
birthYear?: number;
|
|
12
12
|
gender?: 'female' | 'male' | 'other' | 'unknown';
|
|
13
13
|
ncbiTaxonomyId: string;
|
|
14
|
+
breedLabel?: string;
|
|
14
15
|
controllerEmail?: string;
|
|
15
16
|
controllerTelephone?: string;
|
|
16
17
|
sector?: string;
|
|
@@ -24,6 +25,7 @@ export type VetChainAnimalDraftInput = Readonly<{
|
|
|
24
25
|
birthYear?: number;
|
|
25
26
|
gender?: 'female' | 'male' | 'other' | 'unknown';
|
|
26
27
|
ncbiTaxonomyId?: string;
|
|
28
|
+
breedLabel?: string;
|
|
27
29
|
controllerEmail?: string;
|
|
28
30
|
controllerTelephone?: string;
|
|
29
31
|
sector?: string;
|
|
@@ -41,6 +43,7 @@ export declare const VetChainAnimalOnboardingClaimNames: Readonly<{
|
|
|
41
43
|
readonly sameAs: "org.schema.Organization.sameAs";
|
|
42
44
|
readonly memberName: "org.schema.Organization.member.name";
|
|
43
45
|
readonly memberAdditionalType: "org.schema.Organization.member.additionalType";
|
|
46
|
+
readonly memberBreed: "org.schema.Organization.member.breed";
|
|
44
47
|
readonly memberBirthDate: "org.schema.Organization.member.birthDate";
|
|
45
48
|
readonly memberGender: "org.schema.Organization.member.gender";
|
|
46
49
|
readonly memberRole: "org.schema.Organization.member.role";
|
|
@@ -12,6 +12,7 @@ export const VetChainAnimalOnboardingClaimNames = Object.freeze({
|
|
|
12
12
|
sameAs: 'org.schema.Organization.sameAs',
|
|
13
13
|
memberName: 'org.schema.Organization.member.name',
|
|
14
14
|
memberAdditionalType: 'org.schema.Organization.member.additionalType',
|
|
15
|
+
memberBreed: 'org.schema.Organization.member.breed',
|
|
15
16
|
memberBirthDate: 'org.schema.Organization.member.birthDate',
|
|
16
17
|
memberGender: 'org.schema.Organization.member.gender',
|
|
17
18
|
memberRole: 'org.schema.Organization.member.role',
|
|
@@ -37,8 +38,9 @@ export function buildVetChainAnimalDraftClaims(input) {
|
|
|
37
38
|
throw new TypeError('vet_animal_card_species_required');
|
|
38
39
|
if (cardDidWeb)
|
|
39
40
|
assertCardSpecies(cardDidWeb, ncbiTaxonomyId);
|
|
40
|
-
const birthDate = String(input.birthDate || '').trim()
|
|
41
|
-
|| (Number.isInteger(input.birthYear) ? String(input.birthYear) : '');
|
|
41
|
+
const birthDate = normalizePartialBirthDate(String(input.birthDate || '').trim()
|
|
42
|
+
|| (Number.isInteger(input.birthYear) ? String(input.birthYear) : ''));
|
|
43
|
+
const breedLabel = String(input.breedLabel || '').trim();
|
|
42
44
|
const legalName = String(input.legalName || '').trim();
|
|
43
45
|
const gender = input.gender && input.gender !== 'unknown' ? input.gender : '';
|
|
44
46
|
const claim = VetChainAnimalOnboardingClaimNames;
|
|
@@ -55,6 +57,7 @@ export function buildVetChainAnimalDraftClaims(input) {
|
|
|
55
57
|
...(ncbiTaxonomyId ? {
|
|
56
58
|
[claim.memberAdditionalType]: `http://purl.obolibrary.org/obo/NCBITaxon_${ncbiTaxonomyId}`,
|
|
57
59
|
} : {}),
|
|
60
|
+
...(breedLabel ? { [claim.memberBreed]: breedLabel } : {}),
|
|
58
61
|
[claim.memberRole]: VetChainAnimalMemberRoles.Self,
|
|
59
62
|
...(birthDate ? { [claim.memberBirthDate]: birthDate } : {}),
|
|
60
63
|
...(gender ? { [claim.memberGender]: gender } : {}),
|
|
@@ -63,6 +66,26 @@ export function buildVetChainAnimalDraftClaims(input) {
|
|
|
63
66
|
[claim.serviceCategory]: String(input.sector || '').trim() || 'animal-care',
|
|
64
67
|
});
|
|
65
68
|
}
|
|
69
|
+
/** Normalizes ISO 8601 reduced-precision animal birth dates (year, year-month or full date). */
|
|
70
|
+
function normalizePartialBirthDate(value) {
|
|
71
|
+
if (!value)
|
|
72
|
+
return '';
|
|
73
|
+
const match = value.match(/^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?$/);
|
|
74
|
+
if (!match)
|
|
75
|
+
throw new TypeError('vet_animal_birth_date_invalid');
|
|
76
|
+
const year = Number(match[1]);
|
|
77
|
+
const month = match[2] ? Number(match[2]) : undefined;
|
|
78
|
+
const day = match[3] ? Number(match[3]) : undefined;
|
|
79
|
+
if (year < 1000 || year > 9999 || (month !== undefined && (month < 1 || month > 12))) {
|
|
80
|
+
throw new TypeError('vet_animal_birth_date_invalid');
|
|
81
|
+
}
|
|
82
|
+
if (day !== undefined) {
|
|
83
|
+
const lastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
84
|
+
if (day < 1 || day > lastDay)
|
|
85
|
+
throw new TypeError('vet_animal_birth_date_invalid');
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
66
89
|
/** Reports whether an animal draft can be activated and issued a public Card. */
|
|
67
90
|
export function readVetChainAnimalOnboardingReadiness(claims) {
|
|
68
91
|
const claim = VetChainAnimalOnboardingClaimNames;
|
|
@@ -21,6 +21,16 @@ const draft = buildVetChainAnimalDraftClaims({
|
|
|
21
21
|
controllerTelephone: '+12365162385',
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
+
// Optional breed text stays separate from the governed NCBI species. The
|
|
25
|
+
// birth date may safely retain reduced year-month precision.
|
|
26
|
+
buildVetChainAnimalDraftClaims({
|
|
27
|
+
subjectId: crypto.randomUUID(),
|
|
28
|
+
controllerTelephone: '+12365162385',
|
|
29
|
+
ncbiTaxonomyId: '9615',
|
|
30
|
+
breedLabel: 'Beagle',
|
|
31
|
+
birthDate: '2022-01',
|
|
32
|
+
})
|
|
33
|
+
|
|
24
34
|
// Step 2. The draft has member=SELF/ONESELF and owner=controller.
|
|
25
35
|
draft['org.schema.Organization.member.role'] // ONESELF
|
|
26
36
|
draft['org.schema.Organization.owner.telephone'] // verified controller
|
|
@@ -35,3 +45,10 @@ taxonomy, issues the public Card, and resubmits it under the same private
|
|
|
35
45
|
`subjectId`. GW VET alone performs the `pending -> active` transition. A draft
|
|
36
46
|
does not need a clinical `Composition`; the active clinical index is a
|
|
37
47
|
separate document lifecycle.
|
|
48
|
+
|
|
49
|
+
The controller is the author of demographics supplied during this draft. A
|
|
50
|
+
veterinarian later verifies them as attester. That verification locks the
|
|
51
|
+
controller-facing edit path; a correction is a new version authored and
|
|
52
|
+
attested by an authorized veterinarian, never a rewrite of the earlier author.
|
|
53
|
+
Veterinary identity evidence publishes only protected proof and lifecycle
|
|
54
|
+
metadata to the ledger, not raw identity documents or private demographics.
|
package/package.json
CHANGED