vet-sdk-core-ts 0.4.6 → 0.4.7

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
@@ -6,6 +6,18 @@ UHC SDK packages and must not import them.
6
6
  The SDK consumes governed browser-safe values from `vet-data-utils-ts` and
7
7
  owns gateway request construction. GW VET remains the policy authority.
8
8
 
9
+ ## Reusable professional BFF
10
+
11
+ `ReusableProfessionalBffClient` exposes the complete business-level portal
12
+ journey for UHC UNID, VetChain and SOSChain adapters: post-login profile gate,
13
+ organization admission and review, activation, licences, employees, individual
14
+ creation, clinical data, secondary-use consent, Digital Twin search and
15
+ break-glass. Product adapters inject sectors, translations, routes and policy.
16
+ The client rejects GW, wallet, DCR, SMART and VP plumbing from browser payloads.
17
+
18
+ Start with [`docs/101-REUSABLE_PROFESSIONAL_BFF.md`](docs/101-REUSABLE_PROFESSIONAL_BFF.md)
19
+ and its commented snippet.
20
+
9
21
  ## Professional break-glass authorization
10
22
 
11
23
  Node BFFs call `buildVeterinaryBreakGlassSmartAuthorization` with only the
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export * from "./animal-identity.js";
3
3
  export * from "./gateway-contract.js";
4
4
  export * from "./card-issuance.js";
5
5
  export * from "./animal-onboarding.js";
6
+ export * from "./reusable-bff.js";
6
7
  export * from "vet-data-utils-ts";
package/dist/index.js CHANGED
@@ -3,4 +3,5 @@ export * from "./animal-identity.js";
3
3
  export * from "./gateway-contract.js";
4
4
  export * from "./card-issuance.js";
5
5
  export * from "./animal-onboarding.js";
6
+ export * from "./reusable-bff.js";
6
7
  export * from "vet-data-utils-ts";
@@ -0,0 +1,97 @@
1
+ export type ReusableBffProductExtension = Readonly<{
2
+ /** Stable adapter id used for diagnostics; never an authorization claim. */
3
+ productId: string;
4
+ /** Exact governed sectors rendered by this product. Empty means render none. */
5
+ allowedSectors: readonly string[];
6
+ baseUrl?: string;
7
+ routes?: Partial<ReusableProfessionalBffRoutes>;
8
+ fetch?: typeof globalThis.fetch;
9
+ }>;
10
+ export type ReusableProfessionalBffRoutes = Readonly<{
11
+ initialPin: string;
12
+ initialPinUnlock: string;
13
+ profileActivation: string;
14
+ employeeActivation: string;
15
+ applications: string;
16
+ applicationReview: string;
17
+ licenses: string;
18
+ employeeInvitations: string;
19
+ employeeLifecycle: string;
20
+ subject: string;
21
+ digitalTwinSearch: string;
22
+ breakGlass: string;
23
+ }>;
24
+ export declare const DefaultReusableProfessionalBffRoutes: ReusableProfessionalBffRoutes;
25
+ type BusinessPayload = Readonly<Record<string, unknown>>;
26
+ /**
27
+ * Business-level client for the reusable professional BFF shared by UHC UNID,
28
+ * VetChain and SOSChain product adapters.
29
+ *
30
+ * Callers choose business actions only. Firebase/GW tokens, wallet seeds,
31
+ * activation credentials, DIDComm/JWE, DCR, SMART audiences, client assertions
32
+ * and VPs stay inside the BFF and its high-level Node runtime. Product-specific
33
+ * sectors, labels, evidence and policy are injected through the adapter.
34
+ */
35
+ export declare class ReusableProfessionalBffClient {
36
+ private readonly extension;
37
+ readonly profileGate: Readonly<{
38
+ status: () => Promise<unknown>;
39
+ create: (input: Readonly<{
40
+ pin: string;
41
+ repeatPin: string;
42
+ }>) => Promise<unknown>;
43
+ unlock: (input: Readonly<{
44
+ pin: string;
45
+ }>) => Promise<unknown>;
46
+ }>;
47
+ readonly profiles: Readonly<{
48
+ activate: (input: BusinessPayload) => Promise<unknown>;
49
+ activateEmployee: (input: BusinessPayload) => Promise<unknown>;
50
+ }>;
51
+ readonly applications: Readonly<{
52
+ submit: (input: unknown) => Promise<unknown>;
53
+ review: (input: BusinessPayload & Readonly<{
54
+ applicationId: string;
55
+ }>) => Promise<unknown>;
56
+ complete: (input: Readonly<{
57
+ applicationId: string;
58
+ }>) => Promise<unknown>;
59
+ pdf: (input: Readonly<{
60
+ applicationId: string;
61
+ }>) => Promise<unknown>;
62
+ credential: (input: Readonly<{
63
+ applicationId: string;
64
+ }>) => Promise<unknown>;
65
+ }>;
66
+ readonly licenses: Readonly<{
67
+ purchase: (input: BusinessPayload) => Promise<unknown>;
68
+ }>;
69
+ readonly employees: Readonly<{
70
+ invite: (input: BusinessPayload) => Promise<unknown>;
71
+ lifecycle: (input: BusinessPayload) => Promise<unknown>;
72
+ }>;
73
+ readonly subjects: Readonly<{
74
+ create: (input: BusinessPayload) => Promise<unknown>;
75
+ addClinicalData: (input: BusinessPayload) => Promise<unknown>;
76
+ deleteClinicalData: (input: BusinessPayload) => Promise<unknown>;
77
+ permitDigitalTwin: (input: BusinessPayload) => Promise<unknown>;
78
+ }>;
79
+ readonly digitalTwins: Readonly<{
80
+ search: (input: BusinessPayload) => Promise<unknown>;
81
+ }>;
82
+ readonly breakGlass: Readonly<{
83
+ request: (input: BusinessPayload) => Promise<unknown>;
84
+ }>;
85
+ private readonly routes;
86
+ private readonly fetcher;
87
+ private readonly baseUrl;
88
+ constructor(extension: ReusableBffProductExtension);
89
+ private subjectAction;
90
+ private applicationRoute;
91
+ private request;
92
+ }
93
+ export declare class ReusableBffError extends Error {
94
+ readonly status: number;
95
+ constructor(status: number, message: string);
96
+ }
97
+ export {};
@@ -0,0 +1,138 @@
1
+ import { parseReusableOrganizationApplication } from 'vet-data-utils-ts';
2
+ export const DefaultReusableProfessionalBffRoutes = Object.freeze({
3
+ initialPin: '/api/profiles/initial-pin',
4
+ initialPinUnlock: '/api/profiles/initial-pin/unlock',
5
+ profileActivation: '/api/profiles/activation',
6
+ employeeActivation: '/api/employees/activation',
7
+ applications: '/api/test-network/applications',
8
+ applicationReview: '/api/test-network/applications/review',
9
+ licenses: '/api/licenses',
10
+ employeeInvitations: '/api/employees/invitations',
11
+ employeeLifecycle: '/api/employees/lifecycle',
12
+ subject: '/api/subject',
13
+ digitalTwinSearch: '/api/test-twins/search',
14
+ breakGlass: '/api/professional/break-glass',
15
+ });
16
+ /**
17
+ * Business-level client for the reusable professional BFF shared by UHC UNID,
18
+ * VetChain and SOSChain product adapters.
19
+ *
20
+ * Callers choose business actions only. Firebase/GW tokens, wallet seeds,
21
+ * activation credentials, DIDComm/JWE, DCR, SMART audiences, client assertions
22
+ * and VPs stay inside the BFF and its high-level Node runtime. Product-specific
23
+ * sectors, labels, evidence and policy are injected through the adapter.
24
+ */
25
+ export class ReusableProfessionalBffClient {
26
+ constructor(extension) {
27
+ this.extension = extension;
28
+ this.routes = Object.freeze({ ...DefaultReusableProfessionalBffRoutes, ...extension.routes });
29
+ this.fetcher = extension.fetch ?? globalThis.fetch;
30
+ if (typeof this.fetcher !== 'function')
31
+ throw new TypeError('bff_fetch_not_available');
32
+ this.baseUrl = String(extension.baseUrl || '').replace(/\/$/, '');
33
+ required(extension.productId, 'bff_product_id_required');
34
+ this.profileGate = Object.freeze({
35
+ status: () => this.request(this.routes.initialPin, 'GET'),
36
+ create: input => {
37
+ if (input.pin !== input.repeatPin)
38
+ return Promise.reject(new TypeError('profile_pin_confirmation_mismatch'));
39
+ return this.request(this.routes.initialPin, 'POST', input, true);
40
+ },
41
+ unlock: input => this.request(this.routes.initialPinUnlock, 'POST', input, true),
42
+ });
43
+ this.profiles = Object.freeze({
44
+ activate: input => this.request(this.routes.profileActivation, 'POST', input),
45
+ activateEmployee: input => this.request(this.routes.employeeActivation, 'POST', input),
46
+ });
47
+ this.applications = Object.freeze({
48
+ submit: async (input) => {
49
+ const normalized = parseReusableOrganizationApplication({
50
+ ...asRecord(input),
51
+ allowedSectors: this.extension.allowedSectors,
52
+ });
53
+ return this.request(this.routes.applications, 'POST', normalized);
54
+ },
55
+ review: ({ applicationId, ...input }) => this.request(this.routes.applicationReview, 'POST', {
56
+ ...input,
57
+ applicationId: required(applicationId, 'bff_application_id_required'),
58
+ }),
59
+ complete: ({ applicationId }) => this.request(this.applicationRoute(applicationId, 'complete'), 'POST', {}),
60
+ pdf: ({ applicationId }) => this.request(this.applicationRoute(applicationId, 'pdf'), 'GET'),
61
+ credential: ({ applicationId }) => this.request(this.applicationRoute(applicationId, 'credential'), 'GET'),
62
+ });
63
+ this.licenses = Object.freeze({ purchase: input => this.request(this.routes.licenses, 'POST', input) });
64
+ this.employees = Object.freeze({
65
+ invite: input => this.request(this.routes.employeeInvitations, 'POST', input),
66
+ lifecycle: input => this.request(this.routes.employeeLifecycle, 'POST', input),
67
+ });
68
+ this.subjects = Object.freeze({
69
+ create: input => this.subjectAction('create', input),
70
+ addClinicalData: input => this.subjectAction('add-clinical-data', input),
71
+ deleteClinicalData: input => this.subjectAction('delete-clinical-data', input),
72
+ permitDigitalTwin: input => this.subjectAction('permit-digital-twin', input),
73
+ });
74
+ this.digitalTwins = Object.freeze({ search: input => this.request(this.routes.digitalTwinSearch, 'POST', input) });
75
+ this.breakGlass = Object.freeze({ request: input => this.request(this.routes.breakGlass, 'POST', input) });
76
+ }
77
+ subjectAction(action, input) {
78
+ return this.request(this.routes.subject, 'POST', { ...input, action });
79
+ }
80
+ applicationRoute(applicationId, suffix) {
81
+ return `${this.routes.applications}/${encodeURIComponent(required(applicationId, 'bff_application_id_required'))}/${suffix}`;
82
+ }
83
+ async request(path, method, body, allowPin = false) {
84
+ if (body !== undefined)
85
+ assertBusinessPayload(body, allowPin);
86
+ const response = await this.fetcher(`${this.baseUrl}${path}`, {
87
+ method,
88
+ credentials: 'include',
89
+ headers: {
90
+ accept: 'application/json',
91
+ 'x-product-extension': this.extension.productId,
92
+ ...(body === undefined ? {} : { 'content-type': 'application/json' }),
93
+ },
94
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
95
+ });
96
+ const payload = response.status === 204 ? undefined : await response.json().catch(() => undefined);
97
+ if (!response.ok) {
98
+ const error = asRecord(payload).error;
99
+ throw new ReusableBffError(response.status, typeof error === 'string' ? error : 'bff_operation_failed');
100
+ }
101
+ return payload;
102
+ }
103
+ }
104
+ export class ReusableBffError extends Error {
105
+ constructor(status, message) {
106
+ super(message);
107
+ this.status = status;
108
+ this.name = 'ReusableBffError';
109
+ }
110
+ }
111
+ const forbiddenPlumbing = new Set([
112
+ 'access_token', 'activation_code', 'client_assertion', 'client_id', 'id_token',
113
+ 'private_key', 'privatekey', 'seed', 'vp_token', 'wallet_seed', 'walletseed',
114
+ ]);
115
+ function assertBusinessPayload(value, allowPin) {
116
+ if (!value || typeof value !== 'object')
117
+ return;
118
+ if (Array.isArray(value)) {
119
+ value.forEach(item => assertBusinessPayload(item, allowPin));
120
+ return;
121
+ }
122
+ for (const [key, nested] of Object.entries(value)) {
123
+ const normalized = key.toLowerCase();
124
+ if (forbiddenPlumbing.has(normalized) || (!allowPin && normalized.includes('pin'))) {
125
+ throw new TypeError('bff_internal_plumbing_forbidden');
126
+ }
127
+ assertBusinessPayload(nested, allowPin);
128
+ }
129
+ }
130
+ function asRecord(value) {
131
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
132
+ }
133
+ function required(value, error) {
134
+ const normalized = String(value ?? '').trim();
135
+ if (!normalized)
136
+ throw new TypeError(error);
137
+ return normalized;
138
+ }
@@ -0,0 +1,89 @@
1
+ # Reusable professional BFF: beginner guide
2
+
3
+ This is the stable business API shared by the UHC UNID, VetChain and SOSChain
4
+ professional portals. The common client lives in `vet-sdk-core-ts`; each portal
5
+ adds an adapter with its sectors, translations, routes and policy. No `gdc-*`
6
+ repository needs to change when a product adds or documents an extension.
7
+
8
+ ## The three layers
9
+
10
+ 1. The browser calls `ReusableProfessionalBffClient` with business data.
11
+ 2. The product BFF verifies login, profile ownership, PIN/passkey grants and
12
+ policy, then uses its server-only high-level runtime.
13
+ 3. GW validates signed identity, consent and authorization and persists the
14
+ authoritative result.
15
+
16
+ The browser never builds GW paths, DCR requests, DIDComm/JWE envelopes, SMART
17
+ audiences, `client_assertion`, `vp_token`, activation credentials or wallet
18
+ keys. The reusable client rejects those fields.
19
+
20
+ ## Complete common journey
21
+
22
+ | Stage | SDK operation | Product extension |
23
+ |---|---|---|
24
+ | Verified login | portal identity provider | issuer, translations and mail |
25
+ | Profile gate before navigation | `profileGate.status/create/unlock` | PIN/passkey UI |
26
+ | Organization application | `applications.submit` | allowed sectors and localized labels |
27
+ | Human review | `applications.review` | reviewer policy and optional evidence |
28
+ | Evidence document | `applications.pdf/credential` | PDF template and signing policy |
29
+ | Controller activation | `applications.complete`, `profiles.activate` | delivery channel and host route |
30
+ | Seats and employees | `licenses.purchase`, `employees.invite/lifecycle` | roles and payment adapter |
31
+ | Employee activation | `profiles.activateEmployee` | selected approved role |
32
+ | Individual | `subjects.create` | person demographics in UHC/SOSChain; animal demographics in VetChain |
33
+ | Clinical data | `subjects.addClinicalData/deleteClinicalData` | permitted FHIR resources |
34
+ | Secondary use | `subjects.permitDigitalTwin` | purpose/consent policy |
35
+ | Digital Twin | `digitalTwins.search` | governed search profile |
36
+ | Emergency access | `breakGlass.request` | disabled by default; human/animal policy differs |
37
+
38
+ ## Organization application contract
39
+
40
+ - The product supplies the sector allowlist. The form does not hardcode
41
+ “animal”, “healthcare” or any other product label. An empty allowlist renders
42
+ no sector choice and fails closed.
43
+ - Country starts unselected and uses ISO 3166-1 alpha-2. A regional identifier
44
+ uses an ISO 3166-2 subdivision belonging to that country, for example
45
+ `CA-BC` or `ES-MD`. Postal region is separate.
46
+ - There is one official identifier with type `TAX`, `EIN` or `BN`. A second
47
+ `taxId` is forbidden. A later VAT/tax identifier is additional evidence only
48
+ when the official identifier is not already `TAX`.
49
+ - Official licence is separate and optional on Test Network. A later production
50
+ policy may require it for authorized clinical/index writers.
51
+ - Legal representative and technical controller are separate. If they are the
52
+ same person, the product checkbox reuses the verified email and disables the
53
+ duplicate input.
54
+ - The six independent roles are service provider, data provider and data
55
+ consumer for both the individual index and the Digital Twin index.
56
+ - No application contains a PIN. After verified login, the global profile gate
57
+ creates a PIN once for a new account or unlocks the existing profile after a
58
+ reload, before any redirect or application screen.
59
+
60
+ ## PDF and activation licence
61
+
62
+ The PDF `docVersion` is the lowercase SHA-256 of the immutable template bytes.
63
+ Its portal field is the deployed web origin, not the GW hostname. Authorized
64
+ staff review the application, not merely the PDF.
65
+
66
+ Submission goes directly to human review. There is no generic ten-minute PDF
67
+ or legal-representative email OTP. A product extension may verify an official
68
+ registry telephone when that evidence source requires it.
69
+
70
+ After approval, GW `Order` issues the controller activation licence used once
71
+ by exchange and DCR. Test Network delivery may be email; production delivery is
72
+ planned postal verification. The production licence target is one year with a
73
+ renewal warning one month before expiry. Delivery and renewal remain explicit
74
+ TODOs until their live boundary tests exist.
75
+
76
+ ## Product extensions
77
+
78
+ - **VetChain:** animal sectors, animal individual, veterinary clinical data,
79
+ animal Digital Twin and veterinarian-only animal break-glass.
80
+ - **UHC UNID:** health/other governed sectors, human individual and its own
81
+ consent/emergency policy.
82
+ - **SOSChain:** emergency-response sectors and associations; capabilities come
83
+ from its BFF/GW and fail closed when not enabled.
84
+
85
+ Extensions may narrow or disable a common capability. They must never obtain
86
+ authority from a browser-selected role, product id, sector or checkbox.
87
+
88
+ See [`snippets/reusable-professional-bff.ts`](snippets/reusable-professional-bff.ts)
89
+ for a commented integration example.
@@ -0,0 +1,76 @@
1
+ # VetChain animal identity and evidence
2
+
3
+ ## Canonical numeric contract
4
+
5
+ The personal portal, professional portal, PETD and telephone assistant use the
6
+ same ordered identity tuple:
7
+
8
+ ```text
9
+ speciesId7 + jurisdictionCode5 + animalNumericId15
10
+ ```
11
+
12
+ The check digit follows that same passport and voice order:
13
+
14
+ ```text
15
+ checkDigit1 = Damm(speciesId7 + jurisdictionCode5 + animalNumericId15)
16
+ animalIdentifier16 = animalNumericId15 + checkDigit1
17
+ cardNumber21 = jurisdictionCode5 + animalIdentifier16
18
+ ```
19
+
20
+ `speciesId7` is the zero-padded seven-digit projection of the canonical
21
+ `ncbiTaxonomyId`. `jurisdictionCode5` is country3 plus the immutable region2 of
22
+ birth or initial registration. It is not current residence, current location
23
+ or provider. The animal number contains exactly 15 decimal digits for cards,
24
+ DTMF and voice readback.
25
+
26
+ Species is shown separately in PETD/card/QR and is required to validate the
27
+ check digit. The digit detects transcription or inconsistent context; with
28
+ only ten possible results it cannot create uniqueness. An authoritative
29
+ registry must reject two different animals using the same 15-digit number in
30
+ the same jurisdiction and evidence-system namespace.
31
+
32
+ ## Animal Index blockchain asset
33
+
34
+ The permissioned Animal Index uses the exact fixed-width decimal string, not a
35
+ BigInt, hexadecimal conversion or packed representation:
36
+
37
+ ```text
38
+ canonicalNumericId27 = speciesId7 + jurisdictionCode5 + animalNumericId15
39
+ assetId = lowercaseHex(SHA3-256(ASCII(canonicalNumericId27)))
40
+ ```
41
+
42
+ ASCII and UTF-8 produce the same 27 bytes for decimal digits. Keeping the
43
+ fixed-width string preserves leading zeroes and avoids byte-order/length rules;
44
+ converting to a shorter integer byte array provides no meaningful hash-cost
45
+ benefit. SHA-256 is not part of this Animal Index contract; SHA3-256 is the
46
+ minimum accepted algorithm. `checkDigit1` is excluded because it detects capture errors and is not
47
+ identity material.
48
+
49
+ The asset resolves only the currently active index provider, if one exists. It
50
+ contains no animal data and grants no authorization. Provider replacement or
51
+ revocation remains ledger history while current resolution returns only the
52
+ active provider. The deterministic digest is pseudonymous, not encryption, so
53
+ the 27-digit preimage must not be published or logged.
54
+
55
+ ## Evidence systems
56
+
57
+ | System | Individual 15-digit source | Rule |
58
+ | --- | --- | --- |
59
+ | USDA AIN | yes | Exactly 15 digits beginning `840`; `840` tags apply to animals born in the United States. |
60
+ | CFIA ISO 11784 | yes | Exactly 15 digits beginning `124`; Canadian livestock ranges are allocated by CFIA and responsible administrators. |
61
+ | ISO 11784/11785 animal microchip | yes | Global technical system: preserve all 15 digits and retain issuer/registry evidence separately, regardless of location. |
62
+ | Herd mark | no | May identify a group/herd; issuing authority and jurisdiction are separate metadata. |
63
+ | Slap tattoo | no | May identify a herd or location; issuing authority and jurisdiction are separate metadata. |
64
+ | Other tattoo | no | Retain as evidence; never pad, hash or reinterpret it as the numeric animal number. |
65
+
66
+ Sources:
67
+
68
+ - USDA APHIS animal identification: <https://www.aphis.usda.gov/nvap/reference-guide/animal-identification>
69
+ - CFIA approved animal indicators: <https://inspection.canada.ca/en/animal-health/terrestrial-animals/traceability/indicators>
70
+ - ICAR global ISO 11784/11785 device registry: <https://www.icar.org/icar-registry-of-rfid-devices-in-conformance-with-iso-11784-11785/>
71
+ - EU pet passport use of the global standard: <https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32026R0132>
72
+
73
+ Evidence capture never means verification. Portal and telephone clients create
74
+ an unverified draft, preserve the evidence system and exact normalized value,
75
+ and wait for an authoritative registry/issuer check before presenting it as
76
+ verified or using it for signed PETD issuance.
@@ -0,0 +1,42 @@
1
+ import { ReusableProfessionalBffClient } from 'vet-sdk-core-ts/reusable-bff'
2
+
3
+ // The product adapter owns sectors and translations. The browser cannot ask
4
+ // for a sector that the deployed product did not explicitly enable.
5
+ const bff = new ReusableProfessionalBffClient({
6
+ productId: 'vetchain',
7
+ allowedSectors: ['animal-care', 'animal-insurance', 'animal-research', 'animal-tech'],
8
+ })
9
+
10
+ // Run this immediately after verified login and before redirecting anywhere.
11
+ // New accounts call create once; returning/reloaded accounts call unlock.
12
+ const gate = await bff.profileGate.status()
13
+ void gate
14
+
15
+ // The application contains business evidence only: no taxId duplicate, PIN,
16
+ // activation code, wallet seed, client assertion, VP or SMART token.
17
+ await bff.applications.submit({
18
+ sector: 'animal-care',
19
+ officialId: { type: 'BN', value: '704457076' },
20
+ countryCode: 'CA',
21
+ regionalId: true,
22
+ subdivisionCode: 'CA-BC',
23
+ officialLicense: 'CVBC-12345',
24
+ legalRepresentative: { name: 'Legal Representative', email: 'legal@example.test' },
25
+ technicalController: { sameAsLegalRepresentative: true },
26
+ participationRoles: [
27
+ 'individual-index-data-provider',
28
+ 'digital-twin-data-consumer',
29
+ ],
30
+ })
31
+
32
+ // High-level subject, clinical, Digital Twin and break-glass operations use the
33
+ // current authenticated BFF session. Internal GW security plumbing stays on the
34
+ // server and is rejected if a browser tries to include it.
35
+ await bff.subjects.addClinicalData({ resource: { resourceType: 'Observation' } })
36
+ await bff.digitalTwins.search({ section: 'results', text: 'blood', dateFrom: '2026-01-01' })
37
+ await bff.breakGlass.request({
38
+ subjectDid: 'did:web:example:card:vetchain:12409:1234567890123456',
39
+ requestedSections: ['results'],
40
+ incidentId: 'incident-1',
41
+ justification: 'Immediate emergency veterinary treatment is required.',
42
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vet-sdk-core-ts",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "Browser-safe VetChain core contracts and governed animal species identifiers",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Connecting Solution & Applications Ltd",
@@ -31,11 +31,16 @@
31
31
  "./animal-onboarding": {
32
32
  "types": "./dist/animal-onboarding.d.ts",
33
33
  "default": "./dist/animal-onboarding.js"
34
+ },
35
+ "./reusable-bff": {
36
+ "types": "./dist/reusable-bff.d.ts",
37
+ "default": "./dist/reusable-bff.js"
34
38
  }
35
39
  },
36
40
  "files": [
37
41
  "dist",
38
- "README.md"
42
+ "README.md",
43
+ "docs"
39
44
  ],
40
45
  "scripts": {
41
46
  "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
@@ -54,6 +59,6 @@
54
59
  },
55
60
  "dependencies": {
56
61
  "@noble/hashes": "^2.2.0",
57
- "vet-data-utils-ts": "0.3.1"
62
+ "vet-data-utils-ts": "0.4.2"
58
63
  }
59
64
  }