vet-sdk-core-ts 0.4.25 → 0.4.27

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
@@ -32,6 +32,22 @@ The result contains printable vaccination data plus both
32
32
  the validity interval explicitly; FHIR `Immunization.expirationDate` remains
33
33
  the vaccine-batch expiry.
34
34
 
35
+ `pqcProofLookupReference` is separate: it hashes the exact compact SHC JWS so
36
+ `publishVeterinaryHealthCardPqcProofs(...)` and
37
+ `resolveVeterinaryHealthCardPqcProofs(...)` can use a product ledger/resolver
38
+ to retrieve the unchanged detached `pqc:/` proofs from a single printed SHC
39
+ QR when online. It does not replace the offline companion QR labels.
40
+
41
+ ## Private clinic documents and index projection
42
+
43
+ `sealVeterinarySecureClinicMessage(...)` signs the complete FHIR Bundle
44
+ document with ML-DSA-44 and encrypts it to the clinic/controller endpoint with
45
+ ML-KEM-768 plus AES-256-GCM. Its separate index projection contains only each
46
+ source `fullUrl` and the server-policy allowlisted `resource.meta.tag[]`
47
+ codings. Every coding system must be the concrete
48
+ `<ResourceType>.<search-parameter-or-custom>` key; repeated values become one
49
+ CSV flat claim. The GW never receives the encrypted message or private Bundle.
50
+
35
51
  ## USDC payment quotes
36
52
 
37
53
  `vet-sdk-core-ts/payment` separates the payment provider, asset and EVM network
@@ -13,8 +13,26 @@ export type IssuedVeterinaryHealthCardCredential = Readonly<{
13
13
  pqcQr: readonly (readonly string[])[];
14
14
  payloadBytes: Uint8Array;
15
15
  payloadReferences: SmartHealthCardPayloadReferences;
16
+ /** Optional online lookup; separate from payload hashes and the `pqc:/` format. */
17
+ pqcProofLookupReference: string;
16
18
  printData: InternationalHealthCardPrintData;
17
19
  }>;
20
+ export type VeterinaryHealthCardPqcProofRecord = Readonly<{
21
+ lookupReference: string;
22
+ pqcCompanionProofs: readonly string[];
23
+ }>;
24
+ export type VeterinaryHealthCardPqcProofLedger<Receipt = unknown> = Readonly<{
25
+ publish(record: VeterinaryHealthCardPqcProofRecord): Promise<Receipt>;
26
+ resolve(lookupReference: string): Promise<VeterinaryHealthCardPqcProofRecord | undefined>;
27
+ }>;
28
+ /** Browser/server adapter for the Vet product BFF; ledger custody remains behind that boundary. */
29
+ export declare function createVeterinaryHealthCardPqcProofHttpLedger(input: Readonly<{
30
+ baseUrl: string;
31
+ bearerToken?: () => Promise<string | undefined>;
32
+ fetchImpl?: typeof fetch;
33
+ }>): VeterinaryHealthCardPqcProofLedger<Readonly<{
34
+ transactionId: string;
35
+ }>>;
18
36
  /**
19
37
  * Issues transport values only after the caller supplies GW's authoritative
20
38
  * readback Bundle. The tenant issuer owns the standard ES256 signature. Every
@@ -35,6 +53,19 @@ export declare function issueVeterinaryHealthCardCredential(input: Readonly<{
35
53
  }>;
36
54
  pqcQr?: PostQuantumCompanionProofQrOptions;
37
55
  }>): Promise<IssuedVeterinaryHealthCardCredential>;
56
+ /** Publishes only detached proofs under the exact compact-SHC lookup key. */
57
+ export declare function publishVeterinaryHealthCardPqcProofs<Receipt>(input: Readonly<{
58
+ issued: IssuedVeterinaryHealthCardCredential;
59
+ ledger: VeterinaryHealthCardPqcProofLedger<Receipt>;
60
+ }>): Promise<Readonly<{
61
+ lookupReference: string;
62
+ receipt: Receipt;
63
+ }>>;
64
+ /** Resolves companion proofs online from one scanned SHC QR set. */
65
+ export declare function resolveVeterinaryHealthCardPqcProofs(input: Readonly<{
66
+ shcQr: readonly string[];
67
+ ledger: Pick<VeterinaryHealthCardPqcProofLedger, 'resolve'>;
68
+ }>): Promise<readonly string[]>;
38
69
  /** Verifies the standard credential and all scanned companion proofs offline through caller-owned trust resolvers. */
39
70
  export declare function verifyVeterinaryHealthCardCredential(input: Readonly<{
40
71
  shcQr: readonly string[];
@@ -1,6 +1,38 @@
1
- import { assembleSmartHealthCardJws, buildSmartHealthCardPayloadReferences, decodePostQuantumCompanionProofQr, decodeSmartHealthCardPayloadBytes, decodeSmartHealthCardQr, encodePostQuantumCompanionProofUri, encodePostQuantumCompanionProofQr, encodeSmartHealthCardQr, prepareSmartHealthCard, } from 'vet-data-utils-ts/shc';
1
+ import { assembleSmartHealthCardJws, buildSmartHealthCardJwsProofReference, buildSmartHealthCardPayloadReferences, decodePostQuantumCompanionProofQr, decodePostQuantumCompanionProofUri, decodeSmartHealthCardPayloadBytes, decodeSmartHealthCardQr, encodePostQuantumCompanionProofUri, encodePostQuantumCompanionProofQr, encodeSmartHealthCardQr, prepareSmartHealthCard, } from 'vet-data-utils-ts/shc';
2
2
  import { buildInternationalHealthCardPrintData, } from 'vet-data-utils-ts/international-health-card';
3
3
  import { projectClinicalBundleForReading, } from 'vet-data-utils-ts/clinical-bundle-reader';
4
+ /** Browser/server adapter for the Vet product BFF; ledger custody remains behind that boundary. */
5
+ export function createVeterinaryHealthCardPqcProofHttpLedger(input) {
6
+ const baseUrl = input.baseUrl.replace(/\/$/, '');
7
+ const fetchImpl = input.fetchImpl ?? fetch;
8
+ const headers = async () => {
9
+ const token = await input.bearerToken?.();
10
+ return {
11
+ 'Content-Type': 'application/json',
12
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
13
+ };
14
+ };
15
+ return {
16
+ async publish(record) {
17
+ const response = await fetchImpl(baseUrl, {
18
+ method: 'POST', headers: await headers(), body: JSON.stringify(record),
19
+ });
20
+ if (!response.ok)
21
+ throw new Error(`veterinary_health_card_pqc_publish_failed:${response.status}`);
22
+ return await response.json();
23
+ },
24
+ async resolve(lookupReference) {
25
+ const response = await fetchImpl(`${baseUrl}/${encodeURIComponent(lookupReference)}`, {
26
+ method: 'GET', headers: await headers(),
27
+ });
28
+ if (response.status === 404)
29
+ return undefined;
30
+ if (!response.ok)
31
+ throw new Error(`veterinary_health_card_pqc_resolve_failed:${response.status}`);
32
+ return await response.json();
33
+ },
34
+ };
35
+ }
4
36
  /**
5
37
  * Issues transport values only after the caller supplies GW's authoritative
6
38
  * readback Bundle. The tenant issuer owns the standard ES256 signature. Every
@@ -34,6 +66,7 @@ export async function issueVeterinaryHealthCardCredential(input) {
34
66
  pqcQr: detached.map(proof => encodePostQuantumCompanionProofQr(proof, input.pqcQr)),
35
67
  payloadBytes: prepared.payloadBytes,
36
68
  payloadReferences,
69
+ pqcProofLookupReference: buildSmartHealthCardJwsProofReference(compactJws),
37
70
  printData: buildInternationalHealthCardPrintData({
38
71
  authoritativeBundle: input.authoritativeBundle,
39
72
  validFrom: input.print.validFrom,
@@ -43,6 +76,29 @@ export async function issueVeterinaryHealthCardCredential(input) {
43
76
  }),
44
77
  };
45
78
  }
79
+ /** Publishes only detached proofs under the exact compact-SHC lookup key. */
80
+ export async function publishVeterinaryHealthCardPqcProofs(input) {
81
+ input.issued.pqcCompanionProofs.forEach(decodePostQuantumCompanionProofUri);
82
+ const record = {
83
+ lookupReference: input.issued.pqcProofLookupReference,
84
+ pqcCompanionProofs: [...input.issued.pqcCompanionProofs],
85
+ };
86
+ const receipt = await input.ledger.publish(record);
87
+ return { lookupReference: record.lookupReference, receipt };
88
+ }
89
+ /** Resolves companion proofs online from one scanned SHC QR set. */
90
+ export async function resolveVeterinaryHealthCardPqcProofs(input) {
91
+ const compactJws = decodeSmartHealthCardQr(input.shcQr);
92
+ const lookupReference = buildSmartHealthCardJwsProofReference(compactJws);
93
+ const record = await input.ledger.resolve(lookupReference);
94
+ if (!record)
95
+ throw new TypeError('veterinary_health_card_pqc_proof_not_found');
96
+ if (record.lookupReference !== lookupReference) {
97
+ throw new TypeError('veterinary_health_card_pqc_lookup_mismatch');
98
+ }
99
+ record.pqcCompanionProofs.forEach(decodePostQuantumCompanionProofUri);
100
+ return [...record.pqcCompanionProofs];
101
+ }
46
102
  /** Verifies the standard credential and all scanned companion proofs offline through caller-owned trust resolvers. */
47
103
  export async function verifyVeterinaryHealthCardCredential(input) {
48
104
  const compactJws = decodeSmartHealthCardQr(input.shcQr);
package/dist/index.d.ts CHANGED
@@ -7,5 +7,6 @@ export * from "./reusable-bff.js";
7
7
  export * from "./research-study.js";
8
8
  export * from "./payment.js";
9
9
  export * from "./health-card-issuance.js";
10
+ export * from "./secure-clinic-channel.js";
10
11
  export * from "./scheduling.js";
11
12
  export * from "vet-data-utils-ts";
package/dist/index.js CHANGED
@@ -7,5 +7,6 @@ export * from "./reusable-bff.js";
7
7
  export * from "./research-study.js";
8
8
  export * from "./payment.js";
9
9
  export * from "./health-card-issuance.js";
10
+ export * from "./secure-clinic-channel.js";
10
11
  export * from "./scheduling.js";
11
12
  export * from "vet-data-utils-ts";
@@ -0,0 +1,50 @@
1
+ type JsonObject = Record<string, unknown>;
2
+ export interface VeterinarySecureEndpointPublicKeys {
3
+ endpointId: string;
4
+ signingKeyId: string;
5
+ encryptionKeyId: string;
6
+ signingPublicKey: Uint8Array;
7
+ encryptionPublicKey: Uint8Array;
8
+ }
9
+ export interface VeterinarySecureEndpointKeys {
10
+ publicKeys: VeterinarySecureEndpointPublicKeys;
11
+ signingSecretKey: Uint8Array;
12
+ encryptionSecretKey: Uint8Array;
13
+ }
14
+ export interface VeterinaryEncryptedEnvelope {
15
+ mediaType: 'application/didcomm-encrypted+json';
16
+ compactJwe: string;
17
+ }
18
+ export interface VeterinaryIndexProjection {
19
+ entries: Array<{
20
+ fullUrl: string;
21
+ claims: Record<string, string>;
22
+ }>;
23
+ }
24
+ export interface VeterinaryIndexProjectionPolicy {
25
+ allowedResourceTypes: ReadonlySet<string>;
26
+ allowedTagSystems: ReadonlySet<string>;
27
+ }
28
+ export declare function createVeterinarySecureEndpointKeys(endpointId: string): Promise<VeterinarySecureEndpointKeys>;
29
+ export declare function sealVeterinarySecureClinicMessage(input: Readonly<{
30
+ sender: VeterinarySecureEndpointKeys;
31
+ recipient: VeterinarySecureEndpointPublicKeys;
32
+ from: string;
33
+ to: string;
34
+ messageId: string;
35
+ threadId: string;
36
+ bundle: JsonObject;
37
+ indexPolicy: VeterinaryIndexProjectionPolicy;
38
+ }>): Promise<Readonly<{
39
+ envelope: VeterinaryEncryptedEnvelope;
40
+ indexProjection: VeterinaryIndexProjection;
41
+ }>>;
42
+ export declare function openVeterinarySecureClinicMessage(input: Readonly<{
43
+ recipient: VeterinarySecureEndpointKeys;
44
+ senderSigningPublicKey: Uint8Array;
45
+ envelope: VeterinaryEncryptedEnvelope;
46
+ }>): Promise<Readonly<{
47
+ bundle: unknown;
48
+ signatureVerified: true;
49
+ }>>;
50
+ export {};
@@ -0,0 +1,173 @@
1
+ import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js';
2
+ import { ml_kem768 } from '@noble/post-quantum/ml-kem.js';
3
+ const encoder = new TextEncoder();
4
+ const decoder = new TextDecoder();
5
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
6
+ function base64Url(value) {
7
+ const bytes = typeof value === 'string' ? encoder.encode(value) : value;
8
+ let binary = '';
9
+ for (const byte of bytes)
10
+ binary += String.fromCharCode(byte);
11
+ return btoa(binary).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
12
+ }
13
+ function fromBase64Url(value) {
14
+ const padded = value.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - value.length % 4) % 4);
15
+ const binary = atob(padded);
16
+ return Uint8Array.from(binary, character => character.charCodeAt(0));
17
+ }
18
+ function canonicalize(value) {
19
+ if (value === null || typeof value !== 'object')
20
+ return JSON.stringify(value);
21
+ if (Array.isArray(value))
22
+ return `[${value.map(canonicalize).join(',')}]`;
23
+ return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b))
24
+ .map(([key, child]) => `${JSON.stringify(key)}:${canonicalize(child)}`).join(',')}}`;
25
+ }
26
+ async function keyId(prefix, publicKey) {
27
+ const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', publicKey));
28
+ return `${prefix}:${base64Url(digest)}`;
29
+ }
30
+ export async function createVeterinarySecureEndpointKeys(endpointId) {
31
+ const signing = ml_dsa44.keygen();
32
+ const encryption = ml_kem768.keygen();
33
+ return {
34
+ publicKeys: {
35
+ endpointId,
36
+ signingKeyId: await keyId('urn:vetchain:key:ml-dsa-44', signing.publicKey),
37
+ encryptionKeyId: await keyId('urn:vetchain:key:ml-kem-768', encryption.publicKey),
38
+ signingPublicKey: signing.publicKey,
39
+ encryptionPublicKey: encryption.publicKey,
40
+ },
41
+ signingSecretKey: signing.secretKey,
42
+ encryptionSecretKey: encryption.secretKey,
43
+ };
44
+ }
45
+ async function encryptAesGcm(keyBytes, plaintext, aad) {
46
+ const iv = crypto.getRandomValues(new Uint8Array(12));
47
+ const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, ['encrypt']);
48
+ const combined = new Uint8Array(await crypto.subtle.encrypt({
49
+ name: 'AES-GCM', iv: iv, ...(aad ? { additionalData: aad } : {}), tagLength: 128,
50
+ }, key, plaintext));
51
+ return { iv, ciphertext: combined.slice(0, -16), tag: combined.slice(-16) };
52
+ }
53
+ async function decryptAesGcm(keyBytes, iv, ciphertext, tag, aad) {
54
+ const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, ['decrypt']);
55
+ const combined = new Uint8Array(ciphertext.length + tag.length);
56
+ combined.set(ciphertext);
57
+ combined.set(tag, ciphertext.length);
58
+ return new Uint8Array(await crypto.subtle.decrypt({
59
+ name: 'AES-GCM', iv: iv, ...(aad ? { additionalData: aad } : {}), tagLength: 128,
60
+ }, key, combined));
61
+ }
62
+ async function deriveWrapKey(sharedSecret, encryptionKeyId) {
63
+ const source = await crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false, ['deriveBits']);
64
+ return new Uint8Array(await crypto.subtle.deriveBits({
65
+ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(0),
66
+ info: encoder.encode(`VetChain clinic CEK wrap v1\0${encryptionKeyId}`),
67
+ }, source, 256));
68
+ }
69
+ function extractIndexProjection(bundle, policy) {
70
+ var _a;
71
+ if (bundle.resourceType !== 'Bundle' || bundle.type !== 'document' || !Array.isArray(bundle.entry)) {
72
+ throw new Error('The private payload must be a FHIR Bundle document');
73
+ }
74
+ if (bundle.entry[0]?.resource?.resourceType !== 'Composition') {
75
+ throw new Error('A FHIR Bundle document must have Composition as its first entry');
76
+ }
77
+ const entries = [];
78
+ for (const rawEntry of bundle.entry) {
79
+ const entry = rawEntry;
80
+ const resource = entry.resource;
81
+ if (!resource || typeof resource.resourceType !== 'string' || typeof resource.id !== 'string')
82
+ continue;
83
+ if (typeof entry.fullUrl !== 'string')
84
+ throw new Error('Each indexed resource requires an absolute HTTPS fullUrl');
85
+ let parsed;
86
+ try {
87
+ parsed = new URL(entry.fullUrl);
88
+ }
89
+ catch {
90
+ throw new Error('Each indexed resource requires an absolute HTTPS fullUrl');
91
+ }
92
+ const segments = parsed.pathname.split('/').filter(Boolean);
93
+ if (parsed.protocol !== 'https:' || segments.at(-2) !== resource.resourceType
94
+ || segments.at(-1) !== resource.id || !UUID_PATTERN.test(resource.id)) {
95
+ throw new Error('The fullUrl must end in /<ResourceType>/<UUID> matching the resource');
96
+ }
97
+ if (resource.resourceType === 'Binary' && resource.contentType === 'application/pdf') {
98
+ throw new Error('PDF content must be an Attachment inside DocumentReference');
99
+ }
100
+ if (!policy.allowedResourceTypes.has(resource.resourceType))
101
+ continue;
102
+ const tags = resource.meta?.tag;
103
+ if (!Array.isArray(tags))
104
+ continue;
105
+ const grouped = {};
106
+ for (const rawTag of tags) {
107
+ const tag = rawTag;
108
+ if (typeof tag.system !== 'string' || typeof tag.code !== 'string' || !policy.allowedTagSystems.has(tag.system))
109
+ continue;
110
+ if (!tag.system.startsWith(`${resource.resourceType}.`)) {
111
+ throw new Error(`Index claim ${tag.system} must start with ${resource.resourceType}.`);
112
+ }
113
+ ;
114
+ (grouped[_a = tag.system] ?? (grouped[_a] = [])).push(tag.code);
115
+ }
116
+ const claims = Object.fromEntries(Object.entries(grouped).map(([key, values]) => [key, values.join(',')]));
117
+ if (Object.keys(claims).length)
118
+ entries.push({ fullUrl: entry.fullUrl, claims });
119
+ }
120
+ return { entries };
121
+ }
122
+ function sign(sender, plaintext) {
123
+ const header = base64Url(canonicalize({ alg: 'ML-DSA-44', kid: sender.publicKeys.signingKeyId, typ: 'application/didcomm-signed+json' }));
124
+ const payload = base64Url(canonicalize(plaintext));
125
+ return `${header}.${payload}.${base64Url(ml_dsa44.sign(encoder.encode(`${header}.${payload}`), sender.signingSecretKey))}`;
126
+ }
127
+ export async function sealVeterinarySecureClinicMessage(input) {
128
+ const indexProjection = extractIndexProjection(input.bundle, input.indexPolicy);
129
+ const signed = sign(input.sender, {
130
+ id: input.messageId, thid: input.threadId,
131
+ type: 'https://vetchain.app/protocols/private-fhir-document/1.0/ips',
132
+ from: input.from, to: [input.to], created_time: Math.floor(Date.now() / 1000),
133
+ body: { mediaType: 'application/fhir+json', bundle: input.bundle },
134
+ });
135
+ const cek = crypto.getRandomValues(new Uint8Array(32));
136
+ const header = base64Url(canonicalize({
137
+ alg: 'ML-KEM-768+A256GCMKW', enc: 'A256GCM', kid: input.recipient.encryptionKeyId,
138
+ typ: 'application/didcomm-encrypted+json', cty: 'application/didcomm-signed+json',
139
+ }));
140
+ const encrypted = await encryptAesGcm(cek, encoder.encode(signed), encoder.encode(header));
141
+ const encapsulated = ml_kem768.encapsulate(input.recipient.encryptionPublicKey);
142
+ const wrapped = await encryptAesGcm(await deriveWrapKey(encapsulated.sharedSecret, input.recipient.encryptionKeyId), cek);
143
+ const encryptedKey = base64Url(canonicalize({
144
+ kem: base64Url(encapsulated.cipherText), iv: base64Url(wrapped.iv),
145
+ ciphertext: base64Url(wrapped.ciphertext), tag: base64Url(wrapped.tag),
146
+ }));
147
+ return { envelope: { mediaType: 'application/didcomm-encrypted+json', compactJwe: [
148
+ header, encryptedKey, base64Url(encrypted.iv), base64Url(encrypted.ciphertext), base64Url(encrypted.tag),
149
+ ].join('.') }, indexProjection };
150
+ }
151
+ export async function openVeterinarySecureClinicMessage(input) {
152
+ const parts = input.envelope.compactJwe.split('.');
153
+ if (parts.length !== 5)
154
+ throw new Error('Invalid encrypted DIDComm envelope');
155
+ const [headerPart, encryptedKeyPart, iv, ciphertext, tag] = parts;
156
+ const header = JSON.parse(decoder.decode(fromBase64Url(headerPart)));
157
+ if (header.kid !== input.recipient.publicKeys.encryptionKeyId)
158
+ throw new Error('Envelope recipient key does not match');
159
+ const encryptedKey = JSON.parse(decoder.decode(fromBase64Url(encryptedKeyPart)));
160
+ const shared = ml_kem768.decapsulate(fromBase64Url(encryptedKey.kem), input.recipient.encryptionSecretKey);
161
+ const cek = await decryptAesGcm(await deriveWrapKey(shared, input.recipient.publicKeys.encryptionKeyId), fromBase64Url(encryptedKey.iv), fromBase64Url(encryptedKey.ciphertext), fromBase64Url(encryptedKey.tag));
162
+ const signed = decoder.decode(await decryptAesGcm(cek, fromBase64Url(iv), fromBase64Url(ciphertext), fromBase64Url(tag), encoder.encode(headerPart)));
163
+ const [signedHeader, payload, signature, extra] = signed.split('.');
164
+ if (extra !== undefined || !signature)
165
+ throw new Error('Invalid signed DIDComm payload');
166
+ const protectedHeader = JSON.parse(decoder.decode(fromBase64Url(signedHeader)));
167
+ if (protectedHeader.alg !== 'ML-DSA-44' || protectedHeader.typ !== 'application/didcomm-signed+json'
168
+ || !ml_dsa44.verify(fromBase64Url(signature), encoder.encode(`${signedHeader}.${payload}`), input.senderSigningPublicKey)) {
169
+ throw new Error('Invalid ML-DSA signature');
170
+ }
171
+ const plaintext = JSON.parse(decoder.decode(fromBase64Url(payload)));
172
+ return { bundle: (plaintext.body.bundle), signatureVerified: true };
173
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vet-sdk-core-ts",
3
- "version": "0.4.25",
3
+ "version": "0.4.27",
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",
@@ -48,6 +48,10 @@
48
48
  "types": "./dist/health-card-issuance.d.ts",
49
49
  "default": "./dist/health-card-issuance.js"
50
50
  },
51
+ "./secure-clinic-channel": {
52
+ "types": "./dist/secure-clinic-channel.d.ts",
53
+ "default": "./dist/secure-clinic-channel.js"
54
+ },
51
55
  "./scheduling": {
52
56
  "types": "./dist/scheduling.d.ts",
53
57
  "default": "./dist/scheduling.js"
@@ -75,7 +79,8 @@
75
79
  },
76
80
  "dependencies": {
77
81
  "@noble/hashes": "^2.2.0",
82
+ "@noble/post-quantum": "0.5.4",
78
83
  "gdc-common-utils-ts": "2.9.10",
79
- "vet-data-utils-ts": "0.5.15"
84
+ "vet-data-utils-ts": "0.5.17"
80
85
  }
81
86
  }