vet-data-utils-ts 0.5.30 → 0.5.32

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
@@ -189,6 +189,20 @@ for immunologicals); ordinary human ATC is not substituted for it. Veterinary
189
189
  allergy product coding may also use ATCvet, while manifestations use an allowed
190
190
  SNOMED source.
191
191
 
192
+ `vet-data-utils-ts/veterinary-biologic-product` keeps three independent axes:
193
+
194
+ - WHO ATCvet QI is the international medicine classification;
195
+ - the authorized commercial product and its identifier are regional, sourced
196
+ from [EMA UPD](https://medicines.health.europa.eu/veterinary/),
197
+ [USDA APHIS CVB](https://www.aphis.usda.gov/veterinary-biologics/licensed-products)
198
+ or [CFIA CCVB](https://active.inspection.gc.ca/netapp/veterinarybio-bioveterinaire/vetbioe.aspx);
199
+ - `targetDiseases` contains the separately coded diseases/antigens used by
200
+ FHIR `Immunization.protocolApplied.targetDisease`.
201
+
202
+ Source adapters preserve the authority's original product/true/trade names,
203
+ manufacturer, agents and identifiers. Filtering uses reviewed exact NCBI taxa;
204
+ broad words such as “poultry” are source labels, not invented species IDs.
205
+
192
206
  The shared IPS reader boundary is `projectClinicalBundleForReading(...)` from
193
207
  `vet-data-utils-ts/clinical-bundle-reader`. It accepts a native FHIR Bundle
194
208
  (including R4/R5 resources supported by the common normalizer) or resources
@@ -0,0 +1,43 @@
1
+ import { type FlatClaimResourceEntry } from 'sos-data-utils-ts/flat-claim-resource-graph';
2
+ import { type VeterinaryImmunizationCoding } from './immunization-flat-claims.js';
3
+ export type VeterinaryImmunizationDraftAttachment = Readonly<{
4
+ entryId: string;
5
+ identifier: string;
6
+ contentType: 'application/pdf' | 'image/jpeg' | 'image/png';
7
+ contentHash: string;
8
+ title?: string;
9
+ dataBase64?: string;
10
+ }>;
11
+ export type VeterinaryImmunizationDraft = Readonly<{
12
+ status: 'preparation' | 'confirmed';
13
+ administrationDate: string;
14
+ vaccineCode: VeterinaryImmunizationCoding;
15
+ targetDiseases: readonly VeterinaryImmunizationCoding[];
16
+ productName?: string;
17
+ productCode?: VeterinaryImmunizationCoding;
18
+ productIdentifiers: readonly Readonly<{
19
+ system: string;
20
+ value: string;
21
+ }>[];
22
+ manufacturer?: string;
23
+ lotNumber?: string;
24
+ productExpirationDate?: string;
25
+ barcode?: string;
26
+ routeCode?: string;
27
+ siteCode?: string;
28
+ doseValue?: string;
29
+ doseUnit?: string;
30
+ nextDoseDate?: string;
31
+ attachments: readonly VeterinaryImmunizationDraftAttachment[];
32
+ confirmedAt?: string;
33
+ }>;
34
+ /** Normalizes the same reviewable draft for web, chat, WhatsApp and telephone adapters. */
35
+ export declare function prepareVeterinaryImmunizationDraft(input: Partial<Omit<VeterinaryImmunizationDraft, 'status' | 'confirmedAt'>>): VeterinaryImmunizationDraft;
36
+ /** Records the channel's explicit human readback/preview confirmation. */
37
+ export declare function confirmVeterinaryImmunizationDraft(draft: VeterinaryImmunizationDraft, confirmedAt: string): VeterinaryImmunizationDraft;
38
+ /** Completes a confirmed channel draft with server-owned subject and performer coordinates. */
39
+ export declare function materializeVeterinaryImmunizationDraft(draft: VeterinaryImmunizationDraft, context: Readonly<{
40
+ entryId: string;
41
+ animalReference: string;
42
+ performerReference: string;
43
+ }>): readonly FlatClaimResourceEntry[];
@@ -0,0 +1,94 @@
1
+ import { buildDocumentReferenceFlatEntry } from 'sos-data-utils-ts/flat-claim-resource-graph';
2
+ import { buildVeterinaryImmunizationFlatGraph, } from './immunization-flat-claims.js';
3
+ /** Normalizes the same reviewable draft for web, chat, WhatsApp and telephone adapters. */
4
+ export function prepareVeterinaryImmunizationDraft(input) {
5
+ const administrationDate = date(input.administrationDate, 'veterinary_immunization_date_invalid');
6
+ const vaccineCode = coding(input.vaccineCode, 'veterinary_immunization_vaccine_code_required');
7
+ const productExpirationDate = input.productExpirationDate ? date(input.productExpirationDate, 'veterinary_medication_expiration_date_invalid') : undefined;
8
+ const nextDoseDate = input.nextDoseDate ? date(input.nextDoseDate, 'veterinary_immunization_next_dose_date_invalid') : undefined;
9
+ return Object.freeze({
10
+ status: 'preparation', administrationDate, vaccineCode,
11
+ targetDiseases: Object.freeze((input.targetDiseases ?? []).map((value) => coding(value, 'veterinary_immunization_target_disease_invalid'))),
12
+ ...(text(input.productName) ? { productName: text(input.productName) } : {}),
13
+ ...(input.productCode ? { productCode: coding(input.productCode, 'veterinary_immunization_product_code_invalid') } : {}),
14
+ productIdentifiers: Object.freeze((input.productIdentifiers ?? []).map(({ system, value }) => Object.freeze({
15
+ system: required(system, 'veterinary_immunization_product_identifier_invalid'),
16
+ value: required(value, 'veterinary_immunization_product_identifier_invalid'),
17
+ }))),
18
+ ...(text(input.manufacturer) ? { manufacturer: text(input.manufacturer) } : {}),
19
+ ...(text(input.lotNumber) ? { lotNumber: text(input.lotNumber) } : {}),
20
+ ...(productExpirationDate ? { productExpirationDate } : {}),
21
+ ...(text(input.barcode) ? { barcode: text(input.barcode) } : {}),
22
+ ...(text(input.routeCode) ? { routeCode: text(input.routeCode) } : {}),
23
+ ...(text(input.siteCode) ? { siteCode: text(input.siteCode) } : {}),
24
+ ...(text(input.doseValue) ? { doseValue: text(input.doseValue) } : {}),
25
+ ...(text(input.doseUnit) ? { doseUnit: text(input.doseUnit) } : {}),
26
+ ...(nextDoseDate ? { nextDoseDate } : {}),
27
+ attachments: Object.freeze([...(input.attachments ?? [])]),
28
+ });
29
+ }
30
+ /** Records the channel's explicit human readback/preview confirmation. */
31
+ export function confirmVeterinaryImmunizationDraft(draft, confirmedAt) {
32
+ if (draft.status !== 'preparation')
33
+ throw new TypeError('veterinary_immunization_draft_already_confirmed');
34
+ const instant = required(confirmedAt, 'veterinary_immunization_confirmation_time_required');
35
+ if (Number.isNaN(Date.parse(instant)))
36
+ throw new TypeError('veterinary_immunization_confirmation_time_invalid');
37
+ return Object.freeze({ ...draft, status: 'confirmed', confirmedAt: instant });
38
+ }
39
+ /** Completes a confirmed channel draft with server-owned subject and performer coordinates. */
40
+ export function materializeVeterinaryImmunizationDraft(draft, context) {
41
+ if (draft.status !== 'confirmed')
42
+ throw new TypeError('veterinary_immunization_draft_confirmation_required');
43
+ const attachments = draft.attachments.map(attachment => buildDocumentReferenceFlatEntry(attachment));
44
+ const hasMedication = Boolean(draft.productName || draft.productCode || draft.productIdentifiers.length
45
+ || draft.manufacturer || draft.lotNumber || draft.productExpirationDate || draft.barcode);
46
+ return buildVeterinaryImmunizationFlatGraph({
47
+ entryId: required(context.entryId, 'veterinary_immunization_entry_id_required'),
48
+ animalReference: required(context.animalReference, 'veterinary_immunization_animal_reference_required'),
49
+ performerReference: required(context.performerReference, 'veterinary_immunization_performer_required'),
50
+ administrationDate: draft.administrationDate,
51
+ vaccineCode: draft.vaccineCode,
52
+ targetDiseases: draft.targetDiseases,
53
+ ...(draft.routeCode ? { route: { system: 'http://terminology.hl7.org/CodeSystem/v3-RouteOfAdministration', code: draft.routeCode } } : {}),
54
+ ...(draft.siteCode ? { site: { system: 'http://terminology.hl7.org/CodeSystem/v3-ActSite', code: draft.siteCode } } : {}),
55
+ ...(draft.doseValue ? { dose: { value: draft.doseValue, ...(draft.doseUnit ? { unit: draft.doseUnit } : {}) } } : {}),
56
+ ...(draft.nextDoseDate ? { nextDoseDate: draft.nextDoseDate } : {}),
57
+ ...(hasMedication ? { medication: {
58
+ entryId: `${context.entryId}-medication`,
59
+ productName: draft.productName || draft.vaccineCode.display || `${draft.vaccineCode.system}|${draft.vaccineCode.code}`,
60
+ ...(draft.productCode ? { productCode: draft.productCode } : {}),
61
+ identifiers: draft.productIdentifiers,
62
+ ...(draft.manufacturer ? { manufacturer: draft.manufacturer } : {}),
63
+ ...(draft.lotNumber ? { lotNumber: draft.lotNumber } : {}),
64
+ ...(draft.productExpirationDate ? { expirationDate: draft.productExpirationDate } : {}),
65
+ ...(draft.barcode ? { barcode: draft.barcode } : {}),
66
+ } } : {}),
67
+ attachments,
68
+ attachmentEntryIds: attachments.map(({ entryId }) => entryId),
69
+ });
70
+ }
71
+ function coding(value, error) {
72
+ if (!value || typeof value !== 'object')
73
+ throw new TypeError(error);
74
+ const candidate = value;
75
+ return Object.freeze({
76
+ system: required(candidate.system, error), code: required(candidate.code, error),
77
+ ...(text(candidate.display) ? { display: text(candidate.display) } : {}),
78
+ });
79
+ }
80
+ function date(value, error) {
81
+ const normalized = required(value, error);
82
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(normalized) || Number.isNaN(Date.parse(normalized)))
83
+ throw new TypeError(error);
84
+ return normalized;
85
+ }
86
+ function required(value, error) {
87
+ const normalized = text(value);
88
+ if (!normalized)
89
+ throw new TypeError(error);
90
+ return normalized;
91
+ }
92
+ function text(value) {
93
+ return typeof value === 'string' ? value.trim() : '';
94
+ }
@@ -0,0 +1,55 @@
1
+ import { type FlatClaimResourceEntry } from 'sos-data-utils-ts/flat-claim-resource-graph';
2
+ export type VeterinaryImmunizationCoding = Readonly<{
3
+ system: string;
4
+ code: string;
5
+ display?: string;
6
+ }>;
7
+ export type VeterinaryImmunizationFlatInput = Readonly<{
8
+ entryId: string;
9
+ identifier?: string;
10
+ animalReference: string;
11
+ administrationDate: string;
12
+ vaccineCode: VeterinaryImmunizationCoding;
13
+ performerReference: string;
14
+ targetDiseases?: readonly VeterinaryImmunizationCoding[];
15
+ route?: VeterinaryImmunizationCoding;
16
+ site?: VeterinaryImmunizationCoding;
17
+ dose?: Readonly<{
18
+ value: string;
19
+ unit?: string;
20
+ }>;
21
+ nextDoseDate?: string;
22
+ medication?: Readonly<{
23
+ entryId: string;
24
+ productName: string;
25
+ productCode?: VeterinaryImmunizationCoding;
26
+ identifiers?: readonly Readonly<{
27
+ system: string;
28
+ value: string;
29
+ }>[];
30
+ manufacturer?: string;
31
+ lotNumber?: string;
32
+ expirationDate?: string;
33
+ barcode?: string;
34
+ }>;
35
+ attachments?: readonly FlatClaimResourceEntry[];
36
+ attachmentEntryIds?: readonly string[];
37
+ }>;
38
+ /**
39
+ * Creates a version-neutral flat graph. SearchParameter names are preferred
40
+ * (`Immunization.date`, `Medication.expiration-date`) and product evidence is
41
+ * kept in Medication instead of overloading credential validity.
42
+ */
43
+ export declare function buildVeterinaryImmunizationFlatGraph(input: VeterinaryImmunizationFlatInput): readonly FlatClaimResourceEntry[];
44
+ export type FhirExportRelease = 'R4' | 'R5' | 'R6';
45
+ /** Explicit adapter boundary from canonical flat claims to a selected FHIR release. */
46
+ export declare function exportVeterinaryImmunizationFlatGraph(graph: readonly FlatClaimResourceEntry[], release: FhirExportRelease): Readonly<{
47
+ resourceType: 'Bundle';
48
+ type: 'collection';
49
+ entry: readonly Readonly<{
50
+ fullUrl: string;
51
+ resource: Record<string, unknown>;
52
+ }>[];
53
+ }>;
54
+ /** De-identified three-event fixture based on the supplied Canadian certificate; no owner contact data is retained. */
55
+ export declare const NALA_VACCINATION_FLAT_GRAPH_TEST_DATA: readonly FlatClaimResourceEntry[];
@@ -0,0 +1,224 @@
1
+ import { buildDocumentReferenceFlatEntry, buildFlatClaimResourceEntry, linkFlatClaimResourceEntries, } from 'sos-data-utils-ts/flat-claim-resource-graph';
2
+ /**
3
+ * Creates a version-neutral flat graph. SearchParameter names are preferred
4
+ * (`Immunization.date`, `Medication.expiration-date`) and product evidence is
5
+ * kept in Medication instead of overloading credential validity.
6
+ */
7
+ export function buildVeterinaryImmunizationFlatGraph(input) {
8
+ const vaccineCode = codingToken(input.vaccineCode);
9
+ const claims = {
10
+ 'Immunization.status': 'completed',
11
+ 'Immunization.patient': required(input.animalReference, 'veterinary_immunization_animal_reference_required'),
12
+ 'Immunization.date': isoDate(input.administrationDate, 'veterinary_immunization_date_invalid'),
13
+ 'Immunization.vaccine-code': vaccineCode,
14
+ 'Immunization.performer': required(input.performerReference, 'veterinary_immunization_performer_required'),
15
+ };
16
+ if (input.identifier)
17
+ claims['Immunization.identifier'] = required(input.identifier, 'veterinary_immunization_identifier_invalid');
18
+ if (input.vaccineCode.display)
19
+ claims['Immunization.vaccine-code-display'] = input.vaccineCode.display.trim();
20
+ if (input.targetDiseases?.length)
21
+ claims['Immunization.target-disease'] = input.targetDiseases.map(codingToken).join(',');
22
+ if (input.route)
23
+ claims['Immunization.route'] = codingToken(input.route);
24
+ if (input.site)
25
+ claims['Immunization.site'] = codingToken(input.site);
26
+ if (input.dose) {
27
+ claims['Immunization.dose-quantity-value'] = required(input.dose.value, 'veterinary_immunization_dose_invalid');
28
+ if (input.dose.unit)
29
+ claims['Immunization.dose-quantity-unit'] = input.dose.unit.trim();
30
+ }
31
+ const immunization = buildFlatClaimResourceEntry({ entryId: input.entryId, resourceType: 'Immunization', claims });
32
+ const children = [];
33
+ if (input.medication)
34
+ children.push(buildMedicationEntry(input.medication));
35
+ if (input.nextDoseDate) {
36
+ children.push(buildFlatClaimResourceEntry({
37
+ entryId: `${input.entryId}-recommendation`,
38
+ resourceType: 'ImmunizationRecommendation',
39
+ claims: {
40
+ 'ImmunizationRecommendation.patient': input.animalReference,
41
+ 'ImmunizationRecommendation.date': isoDate(input.nextDoseDate, 'veterinary_immunization_next_dose_date_invalid'),
42
+ 'ImmunizationRecommendation.vaccine-code': vaccineCode,
43
+ },
44
+ }));
45
+ }
46
+ for (const attachment of input.attachments ?? []) {
47
+ if (attachment.resourceType !== 'DocumentReference')
48
+ throw new TypeError('veterinary_immunization_attachment_invalid');
49
+ children.push(attachment);
50
+ }
51
+ const graph = uniqueEntries([immunization, ...children]);
52
+ const childEntryIds = [
53
+ ...(input.medication ? [input.medication.entryId] : []),
54
+ ...(input.nextDoseDate ? [`${input.entryId}-recommendation`] : []),
55
+ ...(input.attachmentEntryIds ?? []),
56
+ ];
57
+ return childEntryIds.length
58
+ ? linkFlatClaimResourceEntries(graph, { parentEntryId: input.entryId, childEntryIds })
59
+ : graph;
60
+ }
61
+ function buildMedicationEntry(input) {
62
+ const claims = {
63
+ 'Medication.code': input.productCode ? codingToken(input.productCode) : required(input.productName, 'veterinary_medication_product_required'),
64
+ 'Medication.code-text': required(input.productName, 'veterinary_medication_product_required'),
65
+ };
66
+ if (input.identifiers?.length) {
67
+ claims['Medication.identifier'] = input.identifiers.map(({ system, value }) => (`${required(system, 'veterinary_medication_identifier_invalid')}|${required(value, 'veterinary_medication_identifier_invalid')}`)).join(',');
68
+ }
69
+ if (input.manufacturer)
70
+ claims['Medication.manufacturer'] = input.manufacturer.trim();
71
+ if (input.lotNumber)
72
+ claims['Medication.lot-number'] = input.lotNumber.trim();
73
+ if (input.expirationDate)
74
+ claims['Medication.expiration-date'] = isoDate(input.expirationDate, 'veterinary_medication_expiration_date_invalid');
75
+ if (input.barcode)
76
+ claims['Medication.serial-number'] = input.barcode.trim();
77
+ return buildFlatClaimResourceEntry({ entryId: input.entryId, resourceType: 'Medication', claims });
78
+ }
79
+ /** Explicit adapter boundary from canonical flat claims to a selected FHIR release. */
80
+ export function exportVeterinaryImmunizationFlatGraph(graph, release) {
81
+ const byReference = new Map(graph.map((entry) => [entry.reference, entry]));
82
+ return Object.freeze({
83
+ resourceType: 'Bundle',
84
+ type: 'collection',
85
+ entry: Object.freeze(graph.map((entry) => Object.freeze({
86
+ fullUrl: entry.reference,
87
+ resource: exportEntry(entry, release, byReference),
88
+ }))),
89
+ });
90
+ }
91
+ function exportEntry(entry, release, byReference) {
92
+ const claims = entry.claims;
93
+ if (entry.resourceType === 'Immunization') {
94
+ const vaccineCode = codeableConcept(claims['Immunization.vaccine-code'], claims['Immunization.vaccine-code-display']);
95
+ const children = splitCsv(claims['Immunization.contained-reference-list']).map((reference) => byReference.get(reference)).filter(Boolean);
96
+ const medication = children.find((child) => child?.resourceType === 'Medication');
97
+ const resource = {
98
+ resourceType: 'Immunization', id: entry.entryId, status: claims['Immunization.status'],
99
+ vaccineCode, patient: { reference: claims['Immunization.patient'] },
100
+ occurrenceDateTime: claims['Immunization.date'],
101
+ performer: [{ actor: { reference: claims['Immunization.performer'] } }],
102
+ };
103
+ if (claims['Immunization.identifier'])
104
+ resource.identifier = [{ value: claims['Immunization.identifier'] }];
105
+ if (claims['Immunization.route'])
106
+ resource.route = codeableConcept(claims['Immunization.route']);
107
+ if (claims['Immunization.site'])
108
+ resource.site = codeableConcept(claims['Immunization.site']);
109
+ if (claims['Immunization.target-disease'])
110
+ resource.protocolApplied = [{ targetDisease: splitCsv(claims['Immunization.target-disease']).map((code) => codeableConcept(code)) }];
111
+ if (medication && release !== 'R4')
112
+ resource.administeredProduct = { reference: { reference: medication.reference } };
113
+ return resource;
114
+ }
115
+ if (entry.resourceType === 'Medication') {
116
+ const lotNumber = claims['Medication.lot-number'];
117
+ const expirationDate = claims['Medication.expiration-date'];
118
+ const resource = {
119
+ resourceType: 'Medication', id: entry.entryId,
120
+ code: codeableConcept(claims['Medication.code'], claims['Medication.code-text']),
121
+ };
122
+ if (claims['Medication.identifier'])
123
+ resource.identifier = splitCsv(claims['Medication.identifier']).map(identifierFromToken);
124
+ if (lotNumber || expirationDate)
125
+ resource[release === 'R6' ? 'instance' : 'batch'] = {
126
+ ...(lotNumber ? { lotNumber } : {}), ...(expirationDate ? { expirationDate } : {}),
127
+ };
128
+ return resource;
129
+ }
130
+ if (entry.resourceType === 'ImmunizationRecommendation')
131
+ return {
132
+ resourceType: 'ImmunizationRecommendation', id: entry.entryId,
133
+ patient: { reference: claims['ImmunizationRecommendation.patient'] },
134
+ date: claims['ImmunizationRecommendation.date'],
135
+ recommendation: [{ vaccineCode: [codeableConcept(claims['ImmunizationRecommendation.vaccine-code'])] }],
136
+ };
137
+ if (entry.resourceType === 'DocumentReference')
138
+ return {
139
+ resourceType: 'DocumentReference', id: entry.entryId, status: 'current',
140
+ identifier: [{ value: claims['DocumentReference.identifier'] }],
141
+ content: [{ attachment: {
142
+ contentType: claims['DocumentReference.content-type'],
143
+ ...(claims['DocumentReference.url'] ? { url: claims['DocumentReference.url'] } : {}),
144
+ ...(claims['DocumentReference.title'] ? { title: claims['DocumentReference.title'] } : {}),
145
+ } }],
146
+ };
147
+ return { resourceType: entry.resourceType, id: entry.entryId, meta: { claims: { ...claims } } };
148
+ }
149
+ function codeableConcept(token, display) {
150
+ const value = required(token, 'veterinary_coding_required');
151
+ const separator = value.lastIndexOf('|');
152
+ if (separator <= 0 || separator === value.length - 1)
153
+ return { text: display || value };
154
+ return { coding: [{ system: value.slice(0, separator), code: value.slice(separator + 1), ...(display ? { display } : {}) }] };
155
+ }
156
+ function identifierFromToken(token) {
157
+ const separator = token.lastIndexOf('|');
158
+ return separator > 0 ? { system: token.slice(0, separator), value: token.slice(separator + 1) } : { value: token };
159
+ }
160
+ function codingToken(coding) {
161
+ return `${required(coding.system, 'veterinary_coding_system_required')}|${required(coding.code, 'veterinary_coding_code_required')}`;
162
+ }
163
+ function isoDate(value, error) {
164
+ const normalized = required(value, error);
165
+ if (!/^\d{4}-\d{2}-\d{2}(?:T.*)?$/.test(normalized) || Number.isNaN(Date.parse(normalized)))
166
+ throw new TypeError(error);
167
+ return normalized;
168
+ }
169
+ function required(value, error) {
170
+ if (typeof value !== 'string' || !value.trim())
171
+ throw new TypeError(error);
172
+ return value.trim();
173
+ }
174
+ function splitCsv(value) {
175
+ return value?.split(',').map((item) => item.trim()).filter(Boolean) ?? [];
176
+ }
177
+ function uniqueEntries(entries) {
178
+ const byId = new Map();
179
+ for (const entry of entries) {
180
+ const existing = byId.get(entry.entryId);
181
+ if (existing && existing.reference !== entry.reference)
182
+ throw new TypeError('flat_claim_entry_id_collision');
183
+ byId.set(entry.entryId, existing ?? entry);
184
+ }
185
+ return Object.freeze([...byId.values()]);
186
+ }
187
+ const atcVet = 'http://www.whocc.no/atcvet';
188
+ const certificate = buildDocumentReferenceFlatEntry({
189
+ entryId: 'nala-vaccination-certificate', identifier: 'urn:uuid:nala-vaccination-certificate',
190
+ contentType: 'image/jpeg', contentHash: 'sha256:test-only-nala-certificate-digest', title: 'Vaccination certificate',
191
+ });
192
+ /** De-identified three-event fixture based on the supplied Canadian certificate; no owner contact data is retained. */
193
+ export const NALA_VACCINATION_FLAT_GRAPH_TEST_DATA = uniqueEntries([
194
+ ...buildVeterinaryImmunizationFlatGraph({
195
+ entryId: 'nala-rabies', animalReference: 'Patient/nala', administrationDate: '2024-05-23',
196
+ performerReference: 'PractitionerRole/certificate-veterinarian',
197
+ vaccineCode: { system: atcVet, code: 'QI07AA02', display: 'Inactivated rabies virus vaccines' },
198
+ targetDiseases: [{ system: 'http://snomed.info/sct', code: '14168008', display: 'Rabies' }],
199
+ nextDoseDate: '2027-05-23',
200
+ medication: {
201
+ entryId: 'nala-rabies-product', productName: 'Imrab 3 TF',
202
+ productCode: { system: atcVet, code: 'QI07AA02' }, manufacturer: 'Boehringer Ingelheim',
203
+ identifiers: [
204
+ { system: 'https://inspection.canada.ca/ccvb', value: '820VV/R1.14/R2.1' },
205
+ { system: 'https://www.aphis.usda.gov/cvb/product-code', value: '1905.26' },
206
+ ],
207
+ lotNumber: '18595', expirationDate: '2025-06-28',
208
+ },
209
+ route: { system: 'http://terminology.hl7.org/CodeSystem/v3-RouteOfAdministration', code: 'SQ', display: 'Subcutaneous' },
210
+ attachments: [certificate], attachmentEntryIds: [certificate.entryId],
211
+ }),
212
+ ...buildVeterinaryImmunizationFlatGraph({
213
+ entryId: 'nala-da2plp', animalReference: 'Patient/nala', administrationDate: '2024-05-23',
214
+ performerReference: 'PractitionerRole/certificate-veterinarian',
215
+ vaccineCode: { system: atcVet, code: 'QI07AI02', display: 'Canine viral and bacterial combination vaccines' },
216
+ nextDoseDate: '2025-05-23', attachments: [certificate], attachmentEntryIds: [certificate.entryId],
217
+ }),
218
+ ...buildVeterinaryImmunizationFlatGraph({
219
+ entryId: 'nala-lyme', animalReference: 'Patient/nala', administrationDate: '2024-05-23',
220
+ performerReference: 'PractitionerRole/certificate-veterinarian',
221
+ vaccineCode: { system: atcVet, code: 'QI07AB04', display: 'Borrelia vaccines' },
222
+ nextDoseDate: '2025-05-23', attachments: [certificate], attachmentEntryIds: [certificate.entryId],
223
+ }),
224
+ ]);
package/dist/index.d.ts CHANGED
@@ -10,6 +10,8 @@ export * from './financial.js';
10
10
  export * from './group.js';
11
11
  export * from './health-dcat.js';
12
12
  export * from './immunization.js';
13
+ export * from './immunization-flat-claims.js';
14
+ export * from './immunization-draft.js';
13
15
  export * from './international-health-card.js';
14
16
  export * from './index-projection-tags.js';
15
17
  export * from './insurance-consent.js';
@@ -23,4 +25,5 @@ export * from './research-study.js';
23
25
  export * from './sectors.js';
24
26
  export * from './shc.js';
25
27
  export * from './veterinary-sections.js';
28
+ export * from './veterinary-biologic-product.js';
26
29
  export * from './scheduling.js';
package/dist/index.js CHANGED
@@ -10,6 +10,8 @@ export * from './financial.js';
10
10
  export * from './group.js';
11
11
  export * from './health-dcat.js';
12
12
  export * from './immunization.js';
13
+ export * from './immunization-flat-claims.js';
14
+ export * from './immunization-draft.js';
13
15
  export * from './international-health-card.js';
14
16
  export * from './index-projection-tags.js';
15
17
  export * from './insurance-consent.js';
@@ -23,4 +25,5 @@ export * from './research-study.js';
23
25
  export * from './sectors.js';
24
26
  export * from './shc.js';
25
27
  export * from './veterinary-sections.js';
28
+ export * from './veterinary-biologic-product.js';
26
29
  export * from './scheduling.js';
@@ -0,0 +1,184 @@
1
+ export declare const NcbiTaxonomySystem: "https://www.ncbi.nlm.nih.gov/taxonomy";
2
+ export type VeterinarySpeciesTaxon = Readonly<{
3
+ system: typeof NcbiTaxonomySystem;
4
+ code: string;
5
+ display: string;
6
+ }>;
7
+ /** Exact taxa used by shared animal-product filters; broad groups are not identities. */
8
+ export declare const VeterinarySpeciesTaxonomy: Readonly<{
9
+ readonly Dog: Readonly<{
10
+ system: typeof NcbiTaxonomySystem;
11
+ code: string;
12
+ display: string;
13
+ }>;
14
+ readonly Cat: Readonly<{
15
+ system: typeof NcbiTaxonomySystem;
16
+ code: string;
17
+ display: string;
18
+ }>;
19
+ readonly Horse: Readonly<{
20
+ system: typeof NcbiTaxonomySystem;
21
+ code: string;
22
+ display: string;
23
+ }>;
24
+ readonly Cattle: Readonly<{
25
+ system: typeof NcbiTaxonomySystem;
26
+ code: string;
27
+ display: string;
28
+ }>;
29
+ readonly Pig: Readonly<{
30
+ system: typeof NcbiTaxonomySystem;
31
+ code: string;
32
+ display: string;
33
+ }>;
34
+ readonly Sheep: Readonly<{
35
+ system: typeof NcbiTaxonomySystem;
36
+ code: string;
37
+ display: string;
38
+ }>;
39
+ readonly Goat: Readonly<{
40
+ system: typeof NcbiTaxonomySystem;
41
+ code: string;
42
+ display: string;
43
+ }>;
44
+ readonly Chicken: Readonly<{
45
+ system: typeof NcbiTaxonomySystem;
46
+ code: string;
47
+ display: string;
48
+ }>;
49
+ }>;
50
+ export declare const VeterinaryBiologicAuthorizationRegions: Readonly<{
51
+ readonly EuEea: "EU-EEA";
52
+ readonly Us: "US";
53
+ readonly Ca: "CA";
54
+ }>;
55
+ export type VeterinaryBiologicAuthorizationRegion = typeof VeterinaryBiologicAuthorizationRegions[keyof typeof VeterinaryBiologicAuthorizationRegions];
56
+ export declare const VeterinaryBiologicProductSources: Readonly<{
57
+ readonly EmaUpd: "ema-upd";
58
+ readonly UsdaCvb: "usda-cvb";
59
+ readonly CfiaCcvb: "cfia-ccvb";
60
+ }>;
61
+ export declare const VeterinaryBiologicIdentifierKinds: Readonly<{
62
+ readonly EmaUpdProductId: "eu-upd-product-id";
63
+ readonly UsdaCvbPcn: "usda-cvb-pcn";
64
+ readonly CfiaCcvbNumber: "cfia-ccvb-number";
65
+ readonly UsdaCode: "usda-code";
66
+ }>;
67
+ export type VeterinaryBiologicIdentifierKind = typeof VeterinaryBiologicIdentifierKinds[keyof typeof VeterinaryBiologicIdentifierKinds];
68
+ export type VeterinaryBiologicCoding = Readonly<{
69
+ system: string;
70
+ code: string;
71
+ display?: string;
72
+ }>;
73
+ export type VeterinaryBiologicProduct = Readonly<{
74
+ source: typeof VeterinaryBiologicProductSources[keyof typeof VeterinaryBiologicProductSources];
75
+ authorization: Readonly<{
76
+ region: VeterinaryBiologicAuthorizationRegion;
77
+ identifiers: readonly Readonly<{
78
+ kind: VeterinaryBiologicIdentifierKind;
79
+ value: string;
80
+ }>[];
81
+ }>;
82
+ productName: string;
83
+ trueName?: string;
84
+ tradeNames: readonly string[];
85
+ manufacturer: string;
86
+ species: readonly VeterinarySpeciesTaxon[];
87
+ targetDiseases: readonly VeterinaryBiologicCoding[];
88
+ /** WHO ATCvet QI classifications; never a regional product authorization id. */
89
+ atcVetCodes: readonly string[];
90
+ agents: readonly string[];
91
+ }>;
92
+ /** Validates one authority record without conflating its identifiers with terminology. */
93
+ export declare function parseVeterinaryBiologicProduct(value: unknown): VeterinaryBiologicProduct;
94
+ /** Pure catalog filtering after source adapters have produced governed records. */
95
+ export declare function filterVeterinaryBiologicProducts(products: readonly VeterinaryBiologicProduct[], filter: Readonly<{
96
+ region: VeterinaryBiologicAuthorizationRegion;
97
+ speciesTaxonomyCode: string;
98
+ targetDisease?: Readonly<{
99
+ system: string;
100
+ code: string;
101
+ }>;
102
+ text?: string;
103
+ }>): readonly VeterinaryBiologicProduct[];
104
+ /** Shared synthetic fixtures; identifiers are deliberately test-only, while systems/taxa are canonical. */
105
+ export declare const VETERINARY_BIOLOGIC_PRODUCT_TEST_DATA: Readonly<{
106
+ readonly euDogRabies: Readonly<{
107
+ source: "ema-upd";
108
+ authorization: Readonly<{
109
+ region: "EU-EEA";
110
+ identifiers: readonly Readonly<{
111
+ kind: "eu-upd-product-id";
112
+ value: "test-eu-product-1";
113
+ }>[];
114
+ }>;
115
+ productName: "Test EU canine rabies vaccine";
116
+ tradeNames: readonly string[];
117
+ manufacturer: "Test manufacturer EU";
118
+ species: readonly Readonly<{
119
+ system: typeof NcbiTaxonomySystem;
120
+ code: string;
121
+ display: string;
122
+ }>[];
123
+ targetDiseases: readonly Readonly<{
124
+ system: "http://snomed.info/sct";
125
+ code: "14168008";
126
+ display: "Rabies";
127
+ }>[];
128
+ atcVetCodes: readonly string[];
129
+ agents: readonly string[];
130
+ }>;
131
+ readonly usCattleProduct: Readonly<{
132
+ source: "usda-cvb";
133
+ authorization: Readonly<{
134
+ region: "US";
135
+ identifiers: readonly Readonly<{
136
+ kind: "usda-cvb-pcn";
137
+ value: "test-us-pcn-1";
138
+ }>[];
139
+ }>;
140
+ productName: "Test US cattle biologic";
141
+ trueName: "Test cattle agent vaccine";
142
+ tradeNames: readonly never[];
143
+ manufacturer: "Test manufacturer US";
144
+ species: readonly Readonly<{
145
+ system: typeof NcbiTaxonomySystem;
146
+ code: string;
147
+ display: string;
148
+ }>[];
149
+ targetDiseases: readonly {
150
+ system: string;
151
+ code: string;
152
+ }[];
153
+ atcVetCodes: readonly never[];
154
+ agents: readonly string[];
155
+ }>;
156
+ readonly caDogRabies: Readonly<{
157
+ source: "cfia-ccvb";
158
+ authorization: Readonly<{
159
+ region: "CA";
160
+ identifiers: readonly (Readonly<{
161
+ kind: "cfia-ccvb-number";
162
+ value: "test-ca-ccvb-1";
163
+ }> | Readonly<{
164
+ kind: "usda-code";
165
+ value: "test-usda-code-1";
166
+ }>)[];
167
+ }>;
168
+ productName: "Test Canadian canine rabies vaccine";
169
+ tradeNames: readonly string[];
170
+ manufacturer: "Test manufacturer CA";
171
+ species: readonly Readonly<{
172
+ system: typeof NcbiTaxonomySystem;
173
+ code: string;
174
+ display: string;
175
+ }>[];
176
+ targetDiseases: readonly Readonly<{
177
+ system: "http://snomed.info/sct";
178
+ code: "14168008";
179
+ display: "Rabies";
180
+ }>[];
181
+ atcVetCodes: readonly string[];
182
+ agents: readonly string[];
183
+ }>;
184
+ }>;
@@ -0,0 +1,171 @@
1
+ export const NcbiTaxonomySystem = 'https://www.ncbi.nlm.nih.gov/taxonomy';
2
+ function taxon(code, display) {
3
+ return Object.freeze({ system: NcbiTaxonomySystem, code, display });
4
+ }
5
+ /** Exact taxa used by shared animal-product filters; broad groups are not identities. */
6
+ export const VeterinarySpeciesTaxonomy = Object.freeze({
7
+ Dog: taxon('9615', 'Canis lupus familiaris'),
8
+ Cat: taxon('9685', 'Felis catus'),
9
+ Horse: taxon('9796', 'Equus caballus'),
10
+ Cattle: taxon('9913', 'Bos taurus'),
11
+ Pig: taxon('9823', 'Sus scrofa'),
12
+ Sheep: taxon('9940', 'Ovis aries'),
13
+ Goat: taxon('9925', 'Capra hircus'),
14
+ Chicken: taxon('9031', 'Gallus gallus'),
15
+ });
16
+ export const VeterinaryBiologicAuthorizationRegions = Object.freeze({
17
+ EuEea: 'EU-EEA',
18
+ Us: 'US',
19
+ Ca: 'CA',
20
+ });
21
+ export const VeterinaryBiologicProductSources = Object.freeze({
22
+ EmaUpd: 'ema-upd',
23
+ UsdaCvb: 'usda-cvb',
24
+ CfiaCcvb: 'cfia-ccvb',
25
+ });
26
+ export const VeterinaryBiologicIdentifierKinds = Object.freeze({
27
+ EmaUpdProductId: 'eu-upd-product-id',
28
+ UsdaCvbPcn: 'usda-cvb-pcn',
29
+ CfiaCcvbNumber: 'cfia-ccvb-number',
30
+ UsdaCode: 'usda-code',
31
+ });
32
+ const SOURCE_REGION = Object.freeze({
33
+ [VeterinaryBiologicProductSources.EmaUpd]: VeterinaryBiologicAuthorizationRegions.EuEea,
34
+ [VeterinaryBiologicProductSources.UsdaCvb]: VeterinaryBiologicAuthorizationRegions.Us,
35
+ [VeterinaryBiologicProductSources.CfiaCcvb]: VeterinaryBiologicAuthorizationRegions.Ca,
36
+ });
37
+ const PRIMARY_IDENTIFIER = Object.freeze({
38
+ [VeterinaryBiologicAuthorizationRegions.EuEea]: VeterinaryBiologicIdentifierKinds.EmaUpdProductId,
39
+ [VeterinaryBiologicAuthorizationRegions.Us]: VeterinaryBiologicIdentifierKinds.UsdaCvbPcn,
40
+ [VeterinaryBiologicAuthorizationRegions.Ca]: VeterinaryBiologicIdentifierKinds.CfiaCcvbNumber,
41
+ });
42
+ function required(value, error) {
43
+ if (typeof value !== 'string' || !value.trim())
44
+ throw new TypeError(error);
45
+ return value.trim();
46
+ }
47
+ function strings(value, error) {
48
+ if (!Array.isArray(value))
49
+ throw new TypeError(error);
50
+ const normalized = value.map((item) => required(item, error));
51
+ return Object.freeze([...new Set(normalized)]);
52
+ }
53
+ /** Validates one authority record without conflating its identifiers with terminology. */
54
+ export function parseVeterinaryBiologicProduct(value) {
55
+ if (!value || typeof value !== 'object')
56
+ throw new TypeError('veterinary_biologic_product_invalid');
57
+ const input = value;
58
+ const source = required(input.source, 'veterinary_biologic_source_invalid');
59
+ if (!(source in SOURCE_REGION))
60
+ throw new TypeError('veterinary_biologic_source_invalid');
61
+ const authorizationInput = input.authorization;
62
+ const region = required(authorizationInput?.region, 'veterinary_biologic_authorization_region_invalid');
63
+ if (SOURCE_REGION[source] !== region)
64
+ throw new TypeError('veterinary_biologic_authorization_region_invalid');
65
+ if (!Array.isArray(authorizationInput?.identifiers) || authorizationInput.identifiers.length === 0) {
66
+ throw new TypeError('veterinary_biologic_authorization_identifier_invalid');
67
+ }
68
+ const identifiers = authorizationInput.identifiers.map((entry) => {
69
+ if (!entry || typeof entry !== 'object')
70
+ throw new TypeError('veterinary_biologic_authorization_identifier_invalid');
71
+ const identifier = entry;
72
+ const kind = required(identifier.kind, 'veterinary_biologic_authorization_identifier_invalid');
73
+ if (!Object.values(VeterinaryBiologicIdentifierKinds).includes(kind)) {
74
+ throw new TypeError('veterinary_biologic_authorization_identifier_invalid');
75
+ }
76
+ return Object.freeze({ kind, value: required(identifier.value, 'veterinary_biologic_authorization_identifier_invalid') });
77
+ });
78
+ if (identifiers[0]?.kind !== PRIMARY_IDENTIFIER[region]) {
79
+ throw new TypeError('veterinary_biologic_authorization_identifier_invalid');
80
+ }
81
+ if (identifiers.slice(1).some(({ kind }) => region !== VeterinaryBiologicAuthorizationRegions.Ca
82
+ || kind !== VeterinaryBiologicIdentifierKinds.UsdaCode)) {
83
+ throw new TypeError('veterinary_biologic_authorization_identifier_invalid');
84
+ }
85
+ if (!Array.isArray(input.species) || input.species.length === 0)
86
+ throw new TypeError('veterinary_biologic_species_invalid');
87
+ const species = input.species.map((entry) => {
88
+ if (!entry || typeof entry !== 'object')
89
+ throw new TypeError('veterinary_biologic_species_invalid');
90
+ const candidate = entry;
91
+ if (candidate.system !== NcbiTaxonomySystem)
92
+ throw new TypeError('veterinary_biologic_species_invalid');
93
+ return Object.freeze({
94
+ system: NcbiTaxonomySystem,
95
+ code: required(candidate.code, 'veterinary_biologic_species_invalid'),
96
+ display: required(candidate.display, 'veterinary_biologic_species_invalid'),
97
+ });
98
+ });
99
+ if (!Array.isArray(input.targetDiseases) || input.targetDiseases.length === 0) {
100
+ throw new TypeError('veterinary_biologic_target_disease_invalid');
101
+ }
102
+ const targetDiseases = input.targetDiseases.map((entry) => {
103
+ if (!entry || typeof entry !== 'object')
104
+ throw new TypeError('veterinary_biologic_target_disease_invalid');
105
+ const candidate = entry;
106
+ const display = typeof candidate.display === 'string' && candidate.display.trim() ? candidate.display.trim() : undefined;
107
+ return Object.freeze({
108
+ system: required(candidate.system, 'veterinary_biologic_target_disease_invalid'),
109
+ code: required(candidate.code, 'veterinary_biologic_target_disease_invalid'),
110
+ ...(display ? { display } : {}),
111
+ });
112
+ });
113
+ const atcVetCodes = strings(input.atcVetCodes ?? [], 'veterinary_biologic_atcvet_invalid');
114
+ if (atcVetCodes.some((code) => !/^QI[A-Z0-9]{0,8}$/.test(code)))
115
+ throw new TypeError('veterinary_biologic_atcvet_invalid');
116
+ return Object.freeze({
117
+ source,
118
+ authorization: Object.freeze({ region, identifiers: Object.freeze(identifiers) }),
119
+ productName: required(input.productName, 'veterinary_biologic_product_name_required'),
120
+ ...(typeof input.trueName === 'string' && input.trueName.trim() ? { trueName: input.trueName.trim() } : {}),
121
+ tradeNames: strings(input.tradeNames ?? [], 'veterinary_biologic_trade_name_invalid'),
122
+ manufacturer: required(input.manufacturer, 'veterinary_biologic_manufacturer_required'),
123
+ species: Object.freeze(species),
124
+ targetDiseases: Object.freeze(targetDiseases),
125
+ atcVetCodes,
126
+ agents: strings(input.agents ?? [], 'veterinary_biologic_agent_invalid'),
127
+ });
128
+ }
129
+ /** Pure catalog filtering after source adapters have produced governed records. */
130
+ export function filterVeterinaryBiologicProducts(products, filter) {
131
+ const speciesCode = required(filter.speciesTaxonomyCode, 'veterinary_biologic_species_filter_required');
132
+ const text = String(filter.text || '').trim().toLocaleLowerCase('en');
133
+ return products.filter((product) => product.authorization.region === filter.region)
134
+ .filter((product) => product.species.some(({ code }) => code === speciesCode))
135
+ .filter((product) => !filter.targetDisease || product.targetDiseases.some(({ system, code }) => (system === filter.targetDisease?.system && code === filter.targetDisease.code)))
136
+ .filter((product) => !text || [product.productName, product.trueName, ...product.tradeNames, ...product.agents]
137
+ .filter(Boolean).some((candidate) => String(candidate).toLocaleLowerCase('en').includes(text)));
138
+ }
139
+ const rabies = Object.freeze({ system: 'http://snomed.info/sct', code: '14168008', display: 'Rabies' });
140
+ /** Shared synthetic fixtures; identifiers are deliberately test-only, while systems/taxa are canonical. */
141
+ export const VETERINARY_BIOLOGIC_PRODUCT_TEST_DATA = Object.freeze({
142
+ euDogRabies: Object.freeze({
143
+ source: VeterinaryBiologicProductSources.EmaUpd,
144
+ authorization: Object.freeze({ region: VeterinaryBiologicAuthorizationRegions.EuEea, identifiers: Object.freeze([
145
+ Object.freeze({ kind: VeterinaryBiologicIdentifierKinds.EmaUpdProductId, value: 'test-eu-product-1' }),
146
+ ]) }),
147
+ productName: 'Test EU canine rabies vaccine', tradeNames: Object.freeze(['Test EU Rabies']),
148
+ manufacturer: 'Test manufacturer EU', species: Object.freeze([VeterinarySpeciesTaxonomy.Dog]),
149
+ targetDiseases: Object.freeze([rabies]), atcVetCodes: Object.freeze(['QI07AA90']), agents: Object.freeze(['Rabies virus']),
150
+ }),
151
+ usCattleProduct: Object.freeze({
152
+ source: VeterinaryBiologicProductSources.UsdaCvb,
153
+ authorization: Object.freeze({ region: VeterinaryBiologicAuthorizationRegions.Us, identifiers: Object.freeze([
154
+ Object.freeze({ kind: VeterinaryBiologicIdentifierKinds.UsdaCvbPcn, value: 'test-us-pcn-1' }),
155
+ ]) }),
156
+ productName: 'Test US cattle biologic', trueName: 'Test cattle agent vaccine', tradeNames: Object.freeze([]),
157
+ manufacturer: 'Test manufacturer US', species: Object.freeze([VeterinarySpeciesTaxonomy.Cattle]),
158
+ targetDiseases: Object.freeze([{ system: 'https://example.test/disease', code: 'test-cattle-disease' }]),
159
+ atcVetCodes: Object.freeze([]), agents: Object.freeze(['Test cattle agent']),
160
+ }),
161
+ caDogRabies: Object.freeze({
162
+ source: VeterinaryBiologicProductSources.CfiaCcvb,
163
+ authorization: Object.freeze({ region: VeterinaryBiologicAuthorizationRegions.Ca, identifiers: Object.freeze([
164
+ Object.freeze({ kind: VeterinaryBiologicIdentifierKinds.CfiaCcvbNumber, value: 'test-ca-ccvb-1' }),
165
+ Object.freeze({ kind: VeterinaryBiologicIdentifierKinds.UsdaCode, value: 'test-usda-code-1' }),
166
+ ]) }),
167
+ productName: 'Test Canadian canine rabies vaccine', tradeNames: Object.freeze(['Test CA Rabies']),
168
+ manufacturer: 'Test manufacturer CA', species: Object.freeze([VeterinarySpeciesTaxonomy.Dog]),
169
+ targetDiseases: Object.freeze([rabies]), atcVetCodes: Object.freeze(['QI07AA90']), agents: Object.freeze(['Rabies virus']),
170
+ }),
171
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vet-data-utils-ts",
3
- "version": "0.5.30",
3
+ "version": "0.5.32",
4
4
  "description": "Browser-safe governed VetChain data contracts",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Connecting Solution & Applications Ltd",
@@ -56,6 +56,14 @@
56
56
  "types": "./dist/immunization.d.ts",
57
57
  "default": "./dist/immunization.js"
58
58
  },
59
+ "./immunization-flat-claims": {
60
+ "types": "./dist/immunization-flat-claims.d.ts",
61
+ "default": "./dist/immunization-flat-claims.js"
62
+ },
63
+ "./immunization-draft": {
64
+ "types": "./dist/immunization-draft.d.ts",
65
+ "default": "./dist/immunization-draft.js"
66
+ },
59
67
  "./international-health-card": {
60
68
  "types": "./dist/international-health-card.d.ts",
61
69
  "default": "./dist/international-health-card.js"
@@ -115,6 +123,10 @@
115
123
  "./scheduling": {
116
124
  "types": "./dist/scheduling.d.ts",
117
125
  "default": "./dist/scheduling.js"
126
+ },
127
+ "./veterinary-biologic-product": {
128
+ "types": "./dist/veterinary-biologic-product.d.ts",
129
+ "default": "./dist/veterinary-biologic-product.js"
118
130
  }
119
131
  },
120
132
  "files": [
@@ -138,7 +150,8 @@
138
150
  },
139
151
  "dependencies": {
140
152
  "gdc-common-utils-ts": "2.9.12",
141
- "pako": "^2.2.0"
153
+ "pako": "^2.2.0",
154
+ "sos-data-utils-ts": "0.3.1"
142
155
  },
143
156
  "engines": {
144
157
  "node": ">=20"