vet-sdk-core-ts 0.4.23 → 0.4.25

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.
@@ -1,36 +1,62 @@
1
- import { type VeterinarySchedulingFlatClaimsResource, type VeterinarySchedulingResourceType } from 'vet-data-utils-ts/scheduling';
2
- export type VeterinarySchedulingBatchMethod = 'POST' | 'PUT';
3
- export type VeterinarySchedulingBatch = Readonly<{
1
+ import { type SchedulingFlatClaimsResource, type SchedulingResourceType } from 'vet-data-utils-ts/scheduling';
2
+ export type SchedulingBatchMethod = 'POST' | 'PUT';
3
+ export type SchedulingBatch = Readonly<{
4
4
  data: readonly Readonly<{
5
- type: `${VeterinarySchedulingResourceType}-v5.0.0`;
6
- resource: VeterinarySchedulingFlatClaimsResource;
5
+ type: `${SchedulingResourceType}-v5.0.0`;
6
+ resource: SchedulingFlatClaimsResource;
7
7
  request: Readonly<{
8
- method: VeterinarySchedulingBatchMethod;
8
+ method: SchedulingBatchMethod;
9
9
  url: string;
10
10
  }>;
11
11
  }>[];
12
12
  }>;
13
13
  /**
14
- * Extends the generic GW JSON:API batch boundary for VetChain scheduling.
15
- * Resources are revalidated at this product boundary and remain claims-only.
14
+ * Extends the generic GW JSON:API batch boundary for reusable scheduling.
15
+ * Resources are revalidated at this product boundary; only SearchParameters are indexed.
16
16
  */
17
- export declare function buildVeterinarySchedulingBatch(resources: readonly unknown[], method?: VeterinarySchedulingBatchMethod): VeterinarySchedulingBatch;
18
- /** Builds the governed claims-first search envelope accepted by GW VET. */
19
- export declare function buildVeterinarySchedulingSearch(resourceType: VeterinarySchedulingResourceType, claims: Readonly<Record<string, unknown>>): Readonly<{
17
+ export declare function buildSchedulingBatch(resources: readonly unknown[], method?: SchedulingBatchMethod): SchedulingBatch;
18
+ /** Builds the governed claims-first search envelope accepted by a GW. */
19
+ export declare function buildSchedulingSearch(resourceType: SchedulingResourceType, claims: Readonly<Record<string, unknown>>): Readonly<{
20
20
  data: readonly Readonly<{
21
- resource: Readonly<{
22
- resourceType: VeterinarySchedulingResourceType;
21
+ resource: Readonly<Record<string, unknown> & {
22
+ resourceType: SchedulingResourceType;
23
23
  id: string;
24
- meta: Readonly<{
24
+ meta: Readonly<Record<string, unknown> & {
25
25
  claims: Readonly<Record<string, readonly string[]>>;
26
26
  }>;
27
27
  }>;
28
28
  }>[];
29
29
  }>;
30
+ /** Builds the organization-wide `_search` envelope for responses recorded inside an inclusive time period. */
31
+ export declare function buildAppointmentResponseSearchPeriod(input: Readonly<{
32
+ from: string;
33
+ to: string;
34
+ }>): Readonly<{
35
+ data: readonly Readonly<{
36
+ resource: Readonly<Record<string, unknown> & {
37
+ resourceType: SchedulingResourceType;
38
+ id: string;
39
+ meta: Readonly<Record<string, unknown> & {
40
+ claims: Readonly<Record<string, readonly string[]>>;
41
+ }>;
42
+ }>;
43
+ }>[];
44
+ }>;
45
+ export type AppointmentResponseEmailPayload = Readonly<{
46
+ to: string;
47
+ subject: string;
48
+ text: string;
49
+ metadata: Readonly<Record<string, string>>;
50
+ }>;
51
+ /** Converts the governed English AppointmentResponse Communication projection into an email-adapter payload. */
52
+ export declare function convertAppointmentResponseCommunicationToEnglishEmail(input: Readonly<{
53
+ recipientEmail: string;
54
+ communication: unknown;
55
+ }>): AppointmentResponseEmailPayload;
30
56
  /** Reads canonical GW search matches from `body.data[].resource`. */
31
- export declare function readVeterinarySchedulingSearch(body: unknown, expectedResourceType: VeterinarySchedulingResourceType): readonly VeterinarySchedulingFlatClaimsResource[];
32
- export type VeterinaryScheduleReconciliation = Readonly<{
33
- appointments: readonly VeterinarySchedulingFlatClaimsResource[];
57
+ export declare function readSchedulingSearch(body: unknown, expectedResourceType: SchedulingResourceType): readonly SchedulingFlatClaimsResource[];
58
+ export type ScheduleReconciliation = Readonly<{
59
+ appointments: readonly SchedulingFlatClaimsResource[];
34
60
  notifications: readonly Readonly<{
35
61
  resourceType: 'Communication';
36
62
  id: string;
@@ -44,9 +70,29 @@ export type VeterinaryScheduleReconciliation = Readonly<{
44
70
  * It deliberately does not cancel: the patient receives a durable
45
71
  * Communication and may choose another slot before a final decline.
46
72
  */
47
- export declare function reconcileVeterinaryAppointmentsAfterSlotChange(input: Readonly<{
73
+ export declare function reconcileAppointmentsAfterSlotChange(input: Readonly<{
48
74
  appointments: readonly unknown[];
49
75
  availableSlotReferences: ReadonlySet<string>;
50
- subjectReferenceFor: (appointment: VeterinarySchedulingFlatClaimsResource) => string;
76
+ subjectReferenceFor: (appointment: SchedulingFlatClaimsResource) => string;
51
77
  reason: string;
52
- }>): VeterinaryScheduleReconciliation;
78
+ }>): ScheduleReconciliation;
79
+ /** @deprecated Use {@link SchedulingBatchMethod}. */
80
+ export type VeterinarySchedulingBatchMethod = SchedulingBatchMethod;
81
+ /** @deprecated Use {@link SchedulingBatch}. */
82
+ export type VeterinarySchedulingBatch = SchedulingBatch;
83
+ /** @deprecated Use {@link buildSchedulingBatch}. */
84
+ export declare const buildVeterinarySchedulingBatch: typeof buildSchedulingBatch;
85
+ /** @deprecated Use {@link buildSchedulingSearch}. */
86
+ export declare const buildVeterinarySchedulingSearch: typeof buildSchedulingSearch;
87
+ /** @deprecated Use {@link buildAppointmentResponseSearchPeriod}. */
88
+ export declare const buildVeterinaryAppointmentResponseSearchPeriod: typeof buildAppointmentResponseSearchPeriod;
89
+ /** @deprecated Use {@link AppointmentResponseEmailPayload}. */
90
+ export type VeterinaryAppointmentResponseEmailPayload = AppointmentResponseEmailPayload;
91
+ /** @deprecated Use {@link convertAppointmentResponseCommunicationToEnglishEmail}. */
92
+ export declare const convertVeterinaryAppointmentResponseCommunicationToEnglishEmail: typeof convertAppointmentResponseCommunicationToEnglishEmail;
93
+ /** @deprecated Use {@link readSchedulingSearch}. */
94
+ export declare const readVeterinarySchedulingSearch: typeof readSchedulingSearch;
95
+ /** @deprecated Use {@link ScheduleReconciliation}. */
96
+ export type VeterinaryScheduleReconciliation = ScheduleReconciliation;
97
+ /** @deprecated Use {@link reconcileAppointmentsAfterSlotChange}. */
98
+ export declare const reconcileVeterinaryAppointmentsAfterSlotChange: typeof reconcileAppointmentsAfterSlotChange;
@@ -1,16 +1,16 @@
1
- import { buildVeterinaryAppointmentNotificationResource, normalizeVeterinarySchedulingFlatClaimsResource, } from 'vet-data-utils-ts/scheduling';
1
+ import { buildAppointmentNotificationResource, normalizeSchedulingFlatClaimsResource, } from 'vet-data-utils-ts/scheduling';
2
2
  const asArrayClaims = (claims) => Object.freeze(Object.fromEntries(Object.entries(claims).map(([name, raw]) => [
3
3
  name,
4
4
  Object.freeze((Array.isArray(raw) ? raw : [raw]).map(value => String(value))),
5
5
  ])));
6
6
  /**
7
- * Extends the generic GW JSON:API batch boundary for VetChain scheduling.
8
- * Resources are revalidated at this product boundary and remain claims-only.
7
+ * Extends the generic GW JSON:API batch boundary for reusable scheduling.
8
+ * Resources are revalidated at this product boundary; only SearchParameters are indexed.
9
9
  */
10
- export function buildVeterinarySchedulingBatch(resources, method = 'POST') {
10
+ export function buildSchedulingBatch(resources, method = 'POST') {
11
11
  return Object.freeze({
12
12
  data: Object.freeze(resources.map(candidate => {
13
- const resource = normalizeVeterinarySchedulingFlatClaimsResource(candidate);
13
+ const resource = normalizeSchedulingFlatClaimsResource(candidate);
14
14
  return Object.freeze({
15
15
  type: `${resource.resourceType}-v5.0.0`,
16
16
  resource,
@@ -19,32 +19,56 @@ export function buildVeterinarySchedulingBatch(resources, method = 'POST') {
19
19
  })),
20
20
  });
21
21
  }
22
- /** Builds the governed claims-first search envelope accepted by GW VET. */
23
- export function buildVeterinarySchedulingSearch(resourceType, claims) {
24
- const resource = normalizeVeterinarySchedulingFlatClaimsResource({
22
+ /** Builds the governed claims-first search envelope accepted by a GW. */
23
+ export function buildSchedulingSearch(resourceType, claims) {
24
+ const resource = normalizeSchedulingFlatClaimsResource({
25
25
  resourceType,
26
26
  id: 'search',
27
27
  meta: { claims },
28
28
  });
29
29
  return Object.freeze({ data: Object.freeze([Object.freeze({ resource })]) });
30
30
  }
31
+ /** Builds the organization-wide `_search` envelope for responses recorded inside an inclusive time period. */
32
+ export function buildAppointmentResponseSearchPeriod(input) {
33
+ const from = Date.parse(input.from);
34
+ const to = Date.parse(input.to);
35
+ if (!Number.isFinite(from) || !Number.isFinite(to) || from > to)
36
+ throw new Error('appointment_response_search_period_invalid');
37
+ return buildSchedulingSearch('AppointmentResponse', {
38
+ 'AppointmentResponse._lastUpdated': [`ge${new Date(from).toISOString()}`, `le${new Date(to).toISOString()}`],
39
+ });
40
+ }
41
+ /** Converts the governed English AppointmentResponse Communication projection into an email-adapter payload. */
42
+ export function convertAppointmentResponseCommunicationToEnglishEmail(input) {
43
+ const email = String(input.recipientEmail || '').trim().toLowerCase();
44
+ const resource = input.communication;
45
+ const claims = resource?.resourceType === 'Communication' ? resource?.meta?.claims : undefined;
46
+ const references = Array.isArray(claims?.['Communication.content-reference']) ? claims['Communication.content-reference'].map(String) : [];
47
+ const appointmentResponse = references.find((value) => value.startsWith('AppointmentResponse/'));
48
+ const appointment = references.find((value) => value.startsWith('Appointment/'));
49
+ const text = String(claims?.['Communication.text'] || '').trim();
50
+ const recipient = String(claims?.['Communication.recipient'] || '').trim();
51
+ if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email) || !appointmentResponse || !appointment || !text || !recipient)
52
+ throw new Error('appointment_response_email_invalid');
53
+ return Object.freeze({ to: email, subject: 'Appointment response', text, metadata: Object.freeze({ appointmentResponse, appointment, recipient, language: 'en' }) });
54
+ }
31
55
  /** Reads canonical GW search matches from `body.data[].resource`. */
32
- export function readVeterinarySchedulingSearch(body, expectedResourceType) {
56
+ export function readSchedulingSearch(body, expectedResourceType) {
33
57
  if (!body || typeof body !== 'object' || !Array.isArray(body.data)) {
34
- throw new TypeError('veterinary_scheduling_search_invalid');
58
+ throw new TypeError('scheduling_search_invalid');
35
59
  }
36
60
  return Object.freeze(body.data.map(entry => {
37
61
  if (!entry || typeof entry !== 'object' || !('resource' in entry)) {
38
- throw new TypeError('veterinary_scheduling_search_resource_invalid');
62
+ throw new TypeError('scheduling_search_resource_invalid');
39
63
  }
40
64
  try {
41
- const resource = normalizeVeterinarySchedulingFlatClaimsResource(entry.resource);
65
+ const resource = normalizeSchedulingFlatClaimsResource(entry.resource);
42
66
  if (resource.resourceType !== expectedResourceType)
43
67
  throw new Error('wrong type');
44
68
  return resource;
45
69
  }
46
70
  catch {
47
- throw new TypeError('veterinary_scheduling_search_resource_invalid');
71
+ throw new TypeError('scheduling_search_resource_invalid');
48
72
  }
49
73
  }));
50
74
  }
@@ -53,26 +77,26 @@ export function readVeterinarySchedulingSearch(body, expectedResourceType) {
53
77
  * It deliberately does not cancel: the patient receives a durable
54
78
  * Communication and may choose another slot before a final decline.
55
79
  */
56
- export function reconcileVeterinaryAppointmentsAfterSlotChange(input) {
80
+ export function reconcileAppointmentsAfterSlotChange(input) {
57
81
  const appointments = [];
58
82
  const notifications = [];
59
83
  for (const candidate of input.appointments) {
60
- const appointment = normalizeVeterinarySchedulingFlatClaimsResource(candidate);
84
+ const appointment = normalizeSchedulingFlatClaimsResource(candidate);
61
85
  if (appointment.resourceType !== 'Appointment')
62
- throw new TypeError('veterinary_scheduling_appointment_required');
86
+ throw new TypeError('scheduling_appointment_required');
63
87
  const slots = appointment.meta.claims['Appointment.slot'] ?? [];
64
88
  if (slots.length > 0 && slots.every(slot => input.availableSlotReferences.has(slot)))
65
89
  continue;
66
- const updated = normalizeVeterinarySchedulingFlatClaimsResource({
90
+ const updated = normalizeSchedulingFlatClaimsResource({
67
91
  ...appointment,
68
- meta: { claims: {
92
+ description: input.reason,
93
+ meta: { ...appointment.meta, claims: {
69
94
  ...appointment.meta.claims,
70
95
  'Appointment.status': ['pending'],
71
- 'VeterinaryAppointment.reschedulingReason': [input.reason],
72
96
  } },
73
97
  });
74
98
  appointments.push(updated);
75
- const notification = buildVeterinaryAppointmentNotificationResource({
99
+ const notification = buildAppointmentNotificationResource({
76
100
  id: `${appointment.id}-schedule-change`,
77
101
  appointmentReference: `Appointment/${appointment.id}`,
78
102
  subjectReference: input.subjectReferenceFor(appointment),
@@ -86,3 +110,15 @@ export function reconcileVeterinaryAppointmentsAfterSlotChange(input) {
86
110
  }
87
111
  return Object.freeze({ appointments: Object.freeze(appointments), notifications: Object.freeze(notifications) });
88
112
  }
113
+ /** @deprecated Use {@link buildSchedulingBatch}. */
114
+ export const buildVeterinarySchedulingBatch = buildSchedulingBatch;
115
+ /** @deprecated Use {@link buildSchedulingSearch}. */
116
+ export const buildVeterinarySchedulingSearch = buildSchedulingSearch;
117
+ /** @deprecated Use {@link buildAppointmentResponseSearchPeriod}. */
118
+ export const buildVeterinaryAppointmentResponseSearchPeriod = buildAppointmentResponseSearchPeriod;
119
+ /** @deprecated Use {@link convertAppointmentResponseCommunicationToEnglishEmail}. */
120
+ export const convertVeterinaryAppointmentResponseCommunicationToEnglishEmail = convertAppointmentResponseCommunicationToEnglishEmail;
121
+ /** @deprecated Use {@link readSchedulingSearch}. */
122
+ export const readVeterinarySchedulingSearch = readSchedulingSearch;
123
+ /** @deprecated Use {@link reconcileAppointmentsAfterSlotChange}. */
124
+ export const reconcileVeterinaryAppointmentsAfterSlotChange = reconcileAppointmentsAfterSlotChange;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vet-sdk-core-ts",
3
- "version": "0.4.23",
3
+ "version": "0.4.25",
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",
@@ -76,6 +76,6 @@
76
76
  "dependencies": {
77
77
  "@noble/hashes": "^2.2.0",
78
78
  "gdc-common-utils-ts": "2.9.10",
79
- "vet-data-utils-ts": "0.5.10"
79
+ "vet-data-utils-ts": "0.5.15"
80
80
  }
81
81
  }