@absolutejs/voice 0.0.22-beta.511 → 0.0.22-beta.512
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/dist/angular/index.js +13 -0
- package/dist/bookingFlow.d.ts +43 -0
- package/dist/calendarAdapter.d.ts +47 -0
- package/dist/calendarSlots.d.ts +35 -0
- package/dist/client/index.js +13 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +492 -0
- package/dist/noShowPredictor.d.ts +46 -0
- package/dist/react/index.js +13 -0
- package/dist/reminderScheduler.d.ts +43 -0
- package/dist/svelte/index.js +13 -0
- package/dist/testing/index.js +13 -0
- package/dist/vue/index.js +13 -0
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { VoiceCalendarAdapter, VoiceCalendarAppointment } from "./calendarAdapter";
|
|
2
|
+
import type { VoiceCalendarSlot } from "./calendarSlots";
|
|
3
|
+
export type VoiceBookingFlowStep = "ask-service" | "ask-date" | "ask-time" | "confirm" | "booking" | "booked" | "failed";
|
|
4
|
+
export type VoiceBookingFlowState = {
|
|
5
|
+
step: VoiceBookingFlowStep;
|
|
6
|
+
serviceId?: string;
|
|
7
|
+
serviceDurationMinutes?: number;
|
|
8
|
+
attendees?: string[];
|
|
9
|
+
proposedSlots: VoiceCalendarSlot[];
|
|
10
|
+
selectedSlot?: VoiceCalendarSlot;
|
|
11
|
+
appointment?: VoiceCalendarAppointment;
|
|
12
|
+
error?: string;
|
|
13
|
+
};
|
|
14
|
+
export type VoiceBookingFlowServiceCatalog = {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
durationMinutes: number;
|
|
18
|
+
}[];
|
|
19
|
+
export type CreateVoiceBookingFlowOptions = {
|
|
20
|
+
adapter: VoiceCalendarAdapter;
|
|
21
|
+
calendarId: string;
|
|
22
|
+
services?: VoiceBookingFlowServiceCatalog;
|
|
23
|
+
defaultDurationMinutes?: number;
|
|
24
|
+
initialStep?: VoiceBookingFlowStep;
|
|
25
|
+
maxSlotsPerDay?: number;
|
|
26
|
+
};
|
|
27
|
+
export declare const createVoiceBookingFlow: (options: CreateVoiceBookingFlowOptions) => {
|
|
28
|
+
chooseService: (serviceId: string) => void;
|
|
29
|
+
chooseSlot: (slotIndex: number) => void;
|
|
30
|
+
confirm: (input?: {
|
|
31
|
+
attendees?: string[];
|
|
32
|
+
title?: string;
|
|
33
|
+
notes?: string;
|
|
34
|
+
}) => Promise<VoiceCalendarAppointment | null>;
|
|
35
|
+
getState: () => VoiceBookingFlowState;
|
|
36
|
+
proposeSlotsForDay: (input: {
|
|
37
|
+
fromMs: number;
|
|
38
|
+
toMs: number;
|
|
39
|
+
}) => Promise<VoiceCalendarSlot[]>;
|
|
40
|
+
reset: () => void;
|
|
41
|
+
subscribe(listener: (state: VoiceBookingFlowState) => void): () => void;
|
|
42
|
+
};
|
|
43
|
+
export type VoiceBookingFlow = ReturnType<typeof createVoiceBookingFlow>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { VoiceCalendarBookedRange, VoiceCalendarBusinessHours, VoiceCalendarSlot } from "./calendarSlots";
|
|
2
|
+
export type VoiceCalendarAppointment = {
|
|
3
|
+
id: string;
|
|
4
|
+
calendarId: string;
|
|
5
|
+
startMs: number;
|
|
6
|
+
endMs: number;
|
|
7
|
+
title?: string;
|
|
8
|
+
attendees?: string[];
|
|
9
|
+
notes?: string;
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
createdAt: number;
|
|
12
|
+
status: "scheduled" | "cancelled" | "completed" | "no-show";
|
|
13
|
+
};
|
|
14
|
+
export type VoiceCalendarAvailabilityQuery = {
|
|
15
|
+
calendarId: string;
|
|
16
|
+
fromMs: number;
|
|
17
|
+
toMs: number;
|
|
18
|
+
durationMinutes: number;
|
|
19
|
+
bufferMinutes?: number;
|
|
20
|
+
granularityMinutes?: number;
|
|
21
|
+
maxSlots?: number;
|
|
22
|
+
};
|
|
23
|
+
export type VoiceCalendarBookInput = {
|
|
24
|
+
calendarId: string;
|
|
25
|
+
startMs: number;
|
|
26
|
+
endMs: number;
|
|
27
|
+
title?: string;
|
|
28
|
+
attendees?: string[];
|
|
29
|
+
notes?: string;
|
|
30
|
+
metadata?: Record<string, string>;
|
|
31
|
+
};
|
|
32
|
+
export type VoiceCalendarAdapter = {
|
|
33
|
+
readonly providerName: string;
|
|
34
|
+
listAvailability(query: VoiceCalendarAvailabilityQuery): Promise<VoiceCalendarSlot[]>;
|
|
35
|
+
book(input: VoiceCalendarBookInput): Promise<VoiceCalendarAppointment>;
|
|
36
|
+
cancel(appointmentId: string): Promise<VoiceCalendarAppointment | null>;
|
|
37
|
+
get(appointmentId: string): Promise<VoiceCalendarAppointment | null>;
|
|
38
|
+
reschedule(appointmentId: string, nextStartMs: number, nextEndMs: number): Promise<VoiceCalendarAppointment | null>;
|
|
39
|
+
};
|
|
40
|
+
export type CreateVoiceInMemoryCalendarAdapterOptions = {
|
|
41
|
+
businessHours: VoiceCalendarBusinessHours[];
|
|
42
|
+
timezone?: string;
|
|
43
|
+
bookedRanges?: VoiceCalendarBookedRange[];
|
|
44
|
+
generateId?: () => string;
|
|
45
|
+
now?: () => number;
|
|
46
|
+
};
|
|
47
|
+
export declare const createVoiceInMemoryCalendarAdapter: (options: CreateVoiceInMemoryCalendarAdapterOptions) => VoiceCalendarAdapter;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type VoiceCalendarBusinessHours = {
|
|
2
|
+
weekday: number;
|
|
3
|
+
start: string;
|
|
4
|
+
end: string;
|
|
5
|
+
};
|
|
6
|
+
export type VoiceCalendarBlackout = {
|
|
7
|
+
date: string;
|
|
8
|
+
reason?: string;
|
|
9
|
+
};
|
|
10
|
+
export type VoiceCalendarBookedRange = {
|
|
11
|
+
startMs: number;
|
|
12
|
+
endMs: number;
|
|
13
|
+
};
|
|
14
|
+
export type VoiceCalendarSlot = {
|
|
15
|
+
startMs: number;
|
|
16
|
+
endMs: number;
|
|
17
|
+
durationMinutes: number;
|
|
18
|
+
};
|
|
19
|
+
export type GenerateVoiceCalendarSlotsInput = {
|
|
20
|
+
fromMs: number;
|
|
21
|
+
toMs: number;
|
|
22
|
+
durationMinutes: number;
|
|
23
|
+
bufferMinutes?: number;
|
|
24
|
+
granularityMinutes?: number;
|
|
25
|
+
timezone?: string;
|
|
26
|
+
businessHours: VoiceCalendarBusinessHours[];
|
|
27
|
+
blackoutDates?: VoiceCalendarBlackout[];
|
|
28
|
+
bookedRanges?: VoiceCalendarBookedRange[];
|
|
29
|
+
maxSlots?: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const generateVoiceCalendarSlots: (input: GenerateVoiceCalendarSlotsInput) => VoiceCalendarSlot[];
|
|
32
|
+
export declare const summarizeVoiceCalendarSlot: (slot: VoiceCalendarSlot, options?: {
|
|
33
|
+
timezone?: string;
|
|
34
|
+
locale?: string;
|
|
35
|
+
}) => string;
|
package/dist/client/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|
package/dist/index.d.ts
CHANGED
|
@@ -321,4 +321,14 @@ export { createVoiceSupervisorPresence } from "./supervisorPresence";
|
|
|
321
321
|
export type { CreateVoiceSupervisorPresenceOptions, VoiceSupervisorPresence, VoiceSupervisorPresenceEvent, VoiceSupervisorRole, VoiceSupervisorWatcher, } from "./supervisorPresence";
|
|
322
322
|
export { createVoiceSupervisorPermissions, VOICE_SUPERVISOR_TIER_CAPABILITIES, } from "./supervisorPermissions";
|
|
323
323
|
export type { CreateVoiceSupervisorPermissionsOptions, VoiceSupervisorCapability, VoiceSupervisorPermission, VoiceSupervisorPermissionCheck, VoiceSupervisorPermissions, VoiceSupervisorTier, } from "./supervisorPermissions";
|
|
324
|
+
export { generateVoiceCalendarSlots, summarizeVoiceCalendarSlot, } from "./calendarSlots";
|
|
325
|
+
export type { GenerateVoiceCalendarSlotsInput, VoiceCalendarBlackout, VoiceCalendarBookedRange, VoiceCalendarBusinessHours, VoiceCalendarSlot, } from "./calendarSlots";
|
|
326
|
+
export { createVoiceInMemoryCalendarAdapter } from "./calendarAdapter";
|
|
327
|
+
export type { CreateVoiceInMemoryCalendarAdapterOptions, VoiceCalendarAdapter, VoiceCalendarAppointment, VoiceCalendarAvailabilityQuery, VoiceCalendarBookInput, } from "./calendarAdapter";
|
|
328
|
+
export { createVoiceBookingFlow } from "./bookingFlow";
|
|
329
|
+
export type { CreateVoiceBookingFlowOptions, VoiceBookingFlow, VoiceBookingFlowServiceCatalog, VoiceBookingFlowState, VoiceBookingFlowStep, } from "./bookingFlow";
|
|
330
|
+
export { scoreVoiceNoShowRisk, summarizeVoiceNoShowVerdict, } from "./noShowPredictor";
|
|
331
|
+
export type { VoiceNoShowHistoricalRecord, VoiceNoShowScoreInput, VoiceNoShowSignal, VoiceNoShowVerdict, } from "./noShowPredictor";
|
|
332
|
+
export { createVoiceReminderScheduler, DEFAULT_VOICE_REMINDER_TRIGGERS, } from "./reminderScheduler";
|
|
333
|
+
export type { CreateVoiceReminderSchedulerOptions, ScheduleVoiceRemindersInput, VoiceReminderChannel, VoiceReminderJob, VoiceReminderScheduler, VoiceReminderTrigger, } from "./reminderScheduler";
|
|
324
334
|
export * from "./types";
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|
|
@@ -70,6 +83,115 @@ var __decorateElement = (array, flags, name, decorators, target, extra) => {
|
|
|
70
83
|
};
|
|
71
84
|
var __require = import.meta.require;
|
|
72
85
|
|
|
86
|
+
// src/calendarSlots.ts
|
|
87
|
+
var exports_calendarSlots = {};
|
|
88
|
+
__export(exports_calendarSlots, {
|
|
89
|
+
summarizeVoiceCalendarSlot: () => summarizeVoiceCalendarSlot,
|
|
90
|
+
generateVoiceCalendarSlots: () => generateVoiceCalendarSlots
|
|
91
|
+
});
|
|
92
|
+
var parseHHMM = (value) => {
|
|
93
|
+
const match = /^([0-9]{1,2}):([0-9]{2})$/u.exec(value);
|
|
94
|
+
if (!match)
|
|
95
|
+
throw new Error(`Invalid time string (expected HH:MM): ${value}`);
|
|
96
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
97
|
+
}, partsAt = (ms, timezone) => {
|
|
98
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
99
|
+
day: "2-digit",
|
|
100
|
+
hour: "2-digit",
|
|
101
|
+
hour12: false,
|
|
102
|
+
minute: "2-digit",
|
|
103
|
+
month: "2-digit",
|
|
104
|
+
timeZone: timezone,
|
|
105
|
+
weekday: "short",
|
|
106
|
+
year: "numeric"
|
|
107
|
+
});
|
|
108
|
+
const map = {};
|
|
109
|
+
for (const part of formatter.formatToParts(new Date(ms))) {
|
|
110
|
+
if (part.type !== "literal")
|
|
111
|
+
map[part.type] = part.value;
|
|
112
|
+
}
|
|
113
|
+
const weekdayMap = {
|
|
114
|
+
Fri: 5,
|
|
115
|
+
Mon: 1,
|
|
116
|
+
Sat: 6,
|
|
117
|
+
Sun: 0,
|
|
118
|
+
Thu: 4,
|
|
119
|
+
Tue: 2,
|
|
120
|
+
Wed: 3
|
|
121
|
+
};
|
|
122
|
+
const hourValue = map.hour === "24" ? "00" : map.hour ?? "0";
|
|
123
|
+
return {
|
|
124
|
+
date: `${map.year}-${map.month}-${map.day}`,
|
|
125
|
+
minutes: Number(hourValue) * 60 + Number(map.minute ?? "0"),
|
|
126
|
+
weekday: weekdayMap[map.weekday ?? ""] ?? 0
|
|
127
|
+
};
|
|
128
|
+
}, overlaps = (aStart, aEnd, bStart, bEnd) => aStart < bEnd && bStart < aEnd, generateVoiceCalendarSlots = (input) => {
|
|
129
|
+
if (input.durationMinutes <= 0) {
|
|
130
|
+
throw new Error("durationMinutes must be positive");
|
|
131
|
+
}
|
|
132
|
+
if (input.toMs <= input.fromMs)
|
|
133
|
+
return [];
|
|
134
|
+
const granularity = input.granularityMinutes ?? 15;
|
|
135
|
+
const buffer = input.bufferMinutes ?? 0;
|
|
136
|
+
const max = input.maxSlots ?? Infinity;
|
|
137
|
+
const hoursByDay = new Map;
|
|
138
|
+
for (const block of input.businessHours) {
|
|
139
|
+
const list = hoursByDay.get(block.weekday) ?? [];
|
|
140
|
+
list.push(block);
|
|
141
|
+
hoursByDay.set(block.weekday, list);
|
|
142
|
+
}
|
|
143
|
+
const blackoutDates = new Set((input.blackoutDates ?? []).map((b) => b.date));
|
|
144
|
+
const slots = [];
|
|
145
|
+
const stepMs = granularity * 60000;
|
|
146
|
+
const durationMs = input.durationMinutes * 60000;
|
|
147
|
+
const bufferMs = buffer * 60000;
|
|
148
|
+
let cursor = input.fromMs;
|
|
149
|
+
while (cursor + durationMs <= input.toMs && slots.length < max) {
|
|
150
|
+
const slotEnd = cursor + durationMs;
|
|
151
|
+
const startParts = partsAt(cursor, input.timezone);
|
|
152
|
+
if (blackoutDates.has(startParts.date)) {
|
|
153
|
+
cursor += stepMs;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const dayHours = hoursByDay.get(startParts.weekday);
|
|
157
|
+
if (!dayHours || dayHours.length === 0) {
|
|
158
|
+
cursor += stepMs;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const endParts = partsAt(slotEnd - 1, input.timezone);
|
|
162
|
+
const fitsHours = dayHours.some((block) => {
|
|
163
|
+
const startMin = parseHHMM(block.start);
|
|
164
|
+
const endMin = parseHHMM(block.end);
|
|
165
|
+
return startParts.minutes >= startMin && endParts.minutes < endMin && startParts.date === endParts.date;
|
|
166
|
+
});
|
|
167
|
+
if (!fitsHours) {
|
|
168
|
+
cursor += stepMs;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const collides = (input.bookedRanges ?? []).some((booked) => overlaps(cursor - bufferMs, slotEnd + bufferMs, booked.startMs, booked.endMs));
|
|
172
|
+
if (!collides) {
|
|
173
|
+
slots.push({
|
|
174
|
+
durationMinutes: input.durationMinutes,
|
|
175
|
+
endMs: slotEnd,
|
|
176
|
+
startMs: cursor
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
cursor += stepMs;
|
|
180
|
+
}
|
|
181
|
+
return slots;
|
|
182
|
+
}, summarizeVoiceCalendarSlot = (slot, options = {}) => {
|
|
183
|
+
const formatter = new Intl.DateTimeFormat(options.locale ?? "en-US", {
|
|
184
|
+
day: "numeric",
|
|
185
|
+
hour: "numeric",
|
|
186
|
+
hour12: true,
|
|
187
|
+
minute: "2-digit",
|
|
188
|
+
month: "long",
|
|
189
|
+
timeZone: options.timezone,
|
|
190
|
+
weekday: "long"
|
|
191
|
+
});
|
|
192
|
+
return formatter.format(new Date(slot.startMs));
|
|
193
|
+
};
|
|
194
|
+
|
|
73
195
|
// src/audioConditioning.ts
|
|
74
196
|
var DEFAULT_TARGET_LEVEL = 0.08;
|
|
75
197
|
var DEFAULT_MAX_GAIN = 3;
|
|
@@ -49602,6 +49724,368 @@ var createVoiceSupervisorPermissions = (options = {}) => {
|
|
|
49602
49724
|
};
|
|
49603
49725
|
};
|
|
49604
49726
|
var VOICE_SUPERVISOR_TIER_CAPABILITIES = TIER_CAPABILITIES;
|
|
49727
|
+
// src/calendarAdapter.ts
|
|
49728
|
+
var createVoiceInMemoryCalendarAdapter = (options) => {
|
|
49729
|
+
const now = options.now ?? (() => Date.now());
|
|
49730
|
+
const generateId = options.generateId ?? (() => `appt_${Math.random().toString(36).slice(2, 10)}`);
|
|
49731
|
+
const appointments = new Map;
|
|
49732
|
+
for (const range of options.bookedRanges ?? []) {
|
|
49733
|
+
const id = generateId();
|
|
49734
|
+
appointments.set(id, {
|
|
49735
|
+
calendarId: "default",
|
|
49736
|
+
createdAt: now(),
|
|
49737
|
+
endMs: range.endMs,
|
|
49738
|
+
id,
|
|
49739
|
+
startMs: range.startMs,
|
|
49740
|
+
status: "scheduled"
|
|
49741
|
+
});
|
|
49742
|
+
}
|
|
49743
|
+
const liveRanges = () => Array.from(appointments.values()).filter((a) => a.status === "scheduled").map((a) => ({ endMs: a.endMs, startMs: a.startMs }));
|
|
49744
|
+
return {
|
|
49745
|
+
async book(input) {
|
|
49746
|
+
const clash = liveRanges().some((r) => input.startMs < r.endMs && r.startMs < input.endMs);
|
|
49747
|
+
if (clash)
|
|
49748
|
+
throw new Error("Slot is already booked");
|
|
49749
|
+
const id = generateId();
|
|
49750
|
+
const appointment = {
|
|
49751
|
+
calendarId: input.calendarId,
|
|
49752
|
+
createdAt: now(),
|
|
49753
|
+
endMs: input.endMs,
|
|
49754
|
+
id,
|
|
49755
|
+
startMs: input.startMs,
|
|
49756
|
+
status: "scheduled",
|
|
49757
|
+
...input.title !== undefined ? { title: input.title } : {},
|
|
49758
|
+
...input.attendees !== undefined ? { attendees: input.attendees } : {},
|
|
49759
|
+
...input.notes !== undefined ? { notes: input.notes } : {},
|
|
49760
|
+
...input.metadata !== undefined ? { metadata: input.metadata } : {}
|
|
49761
|
+
};
|
|
49762
|
+
appointments.set(id, appointment);
|
|
49763
|
+
return appointment;
|
|
49764
|
+
},
|
|
49765
|
+
async cancel(id) {
|
|
49766
|
+
const existing = appointments.get(id);
|
|
49767
|
+
if (!existing)
|
|
49768
|
+
return null;
|
|
49769
|
+
const cancelled = {
|
|
49770
|
+
...existing,
|
|
49771
|
+
status: "cancelled"
|
|
49772
|
+
};
|
|
49773
|
+
appointments.set(id, cancelled);
|
|
49774
|
+
return cancelled;
|
|
49775
|
+
},
|
|
49776
|
+
async get(id) {
|
|
49777
|
+
return appointments.get(id) ?? null;
|
|
49778
|
+
},
|
|
49779
|
+
async listAvailability(query) {
|
|
49780
|
+
const { generateVoiceCalendarSlots: generateVoiceCalendarSlots2 } = await Promise.resolve().then(() => exports_calendarSlots);
|
|
49781
|
+
return generateVoiceCalendarSlots2({
|
|
49782
|
+
bookedRanges: liveRanges(),
|
|
49783
|
+
...query.bufferMinutes !== undefined ? { bufferMinutes: query.bufferMinutes } : {},
|
|
49784
|
+
businessHours: options.businessHours,
|
|
49785
|
+
durationMinutes: query.durationMinutes,
|
|
49786
|
+
fromMs: query.fromMs,
|
|
49787
|
+
...query.granularityMinutes !== undefined ? { granularityMinutes: query.granularityMinutes } : {},
|
|
49788
|
+
...query.maxSlots !== undefined ? { maxSlots: query.maxSlots } : {},
|
|
49789
|
+
...options.timezone !== undefined ? { timezone: options.timezone } : {},
|
|
49790
|
+
toMs: query.toMs
|
|
49791
|
+
});
|
|
49792
|
+
},
|
|
49793
|
+
providerName: "in-memory",
|
|
49794
|
+
async reschedule(id, nextStartMs, nextEndMs) {
|
|
49795
|
+
const existing = appointments.get(id);
|
|
49796
|
+
if (!existing)
|
|
49797
|
+
return null;
|
|
49798
|
+
const others = liveRanges().filter((r) => r.startMs !== existing.startMs || r.endMs !== existing.endMs);
|
|
49799
|
+
const clash = others.some((r) => nextStartMs < r.endMs && r.startMs < nextEndMs);
|
|
49800
|
+
if (clash)
|
|
49801
|
+
throw new Error("Cannot reschedule onto a booked slot");
|
|
49802
|
+
const updated = {
|
|
49803
|
+
...existing,
|
|
49804
|
+
endMs: nextEndMs,
|
|
49805
|
+
startMs: nextStartMs
|
|
49806
|
+
};
|
|
49807
|
+
appointments.set(id, updated);
|
|
49808
|
+
return updated;
|
|
49809
|
+
}
|
|
49810
|
+
};
|
|
49811
|
+
};
|
|
49812
|
+
// src/bookingFlow.ts
|
|
49813
|
+
var createVoiceBookingFlow = (options) => {
|
|
49814
|
+
const initial = {
|
|
49815
|
+
proposedSlots: [],
|
|
49816
|
+
step: options.initialStep ?? (options.services ? "ask-service" : "ask-date")
|
|
49817
|
+
};
|
|
49818
|
+
let state = initial;
|
|
49819
|
+
const listeners = new Set;
|
|
49820
|
+
const setState = (next) => {
|
|
49821
|
+
state = { ...state, ...next };
|
|
49822
|
+
for (const listener of listeners)
|
|
49823
|
+
listener(state);
|
|
49824
|
+
};
|
|
49825
|
+
const chooseService = (serviceId) => {
|
|
49826
|
+
const services = options.services ?? [];
|
|
49827
|
+
const service = services.find((s) => s.id === serviceId);
|
|
49828
|
+
if (!service) {
|
|
49829
|
+
setState({ error: `Unknown service: ${serviceId}`, step: "failed" });
|
|
49830
|
+
return;
|
|
49831
|
+
}
|
|
49832
|
+
setState({
|
|
49833
|
+
serviceDurationMinutes: service.durationMinutes,
|
|
49834
|
+
serviceId: service.id,
|
|
49835
|
+
step: "ask-date"
|
|
49836
|
+
});
|
|
49837
|
+
};
|
|
49838
|
+
const proposeSlotsForDay = async (input) => {
|
|
49839
|
+
const duration = state.serviceDurationMinutes ?? options.defaultDurationMinutes ?? 30;
|
|
49840
|
+
const slots = await options.adapter.listAvailability({
|
|
49841
|
+
calendarId: options.calendarId,
|
|
49842
|
+
durationMinutes: duration,
|
|
49843
|
+
fromMs: input.fromMs,
|
|
49844
|
+
...options.maxSlotsPerDay !== undefined ? { maxSlots: options.maxSlotsPerDay } : {},
|
|
49845
|
+
toMs: input.toMs
|
|
49846
|
+
});
|
|
49847
|
+
setState({ proposedSlots: slots, step: slots.length > 0 ? "ask-time" : "ask-date" });
|
|
49848
|
+
return slots;
|
|
49849
|
+
};
|
|
49850
|
+
const chooseSlot = (slotIndex) => {
|
|
49851
|
+
const slot = state.proposedSlots[slotIndex];
|
|
49852
|
+
if (!slot) {
|
|
49853
|
+
setState({ error: "Invalid slot selection", step: "failed" });
|
|
49854
|
+
return;
|
|
49855
|
+
}
|
|
49856
|
+
setState({ selectedSlot: slot, step: "confirm" });
|
|
49857
|
+
};
|
|
49858
|
+
const confirm = async (input = {}) => {
|
|
49859
|
+
if (state.step !== "confirm" || !state.selectedSlot) {
|
|
49860
|
+
setState({ error: "Nothing to confirm", step: "failed" });
|
|
49861
|
+
return null;
|
|
49862
|
+
}
|
|
49863
|
+
setState({ step: "booking" });
|
|
49864
|
+
try {
|
|
49865
|
+
const appt = await options.adapter.book({
|
|
49866
|
+
calendarId: options.calendarId,
|
|
49867
|
+
endMs: state.selectedSlot.endMs,
|
|
49868
|
+
startMs: state.selectedSlot.startMs,
|
|
49869
|
+
...input.attendees !== undefined ? { attendees: input.attendees } : {},
|
|
49870
|
+
...input.title !== undefined ? { title: input.title } : {},
|
|
49871
|
+
...input.notes !== undefined ? { notes: input.notes } : {}
|
|
49872
|
+
});
|
|
49873
|
+
setState({ appointment: appt, step: "booked" });
|
|
49874
|
+
return appt;
|
|
49875
|
+
} catch (error) {
|
|
49876
|
+
setState({
|
|
49877
|
+
error: error instanceof Error ? error.message : String(error),
|
|
49878
|
+
step: "failed"
|
|
49879
|
+
});
|
|
49880
|
+
return null;
|
|
49881
|
+
}
|
|
49882
|
+
};
|
|
49883
|
+
const reset = () => {
|
|
49884
|
+
state = {
|
|
49885
|
+
proposedSlots: [],
|
|
49886
|
+
step: options.initialStep ?? (options.services ? "ask-service" : "ask-date")
|
|
49887
|
+
};
|
|
49888
|
+
for (const listener of listeners)
|
|
49889
|
+
listener(state);
|
|
49890
|
+
};
|
|
49891
|
+
return {
|
|
49892
|
+
chooseService,
|
|
49893
|
+
chooseSlot,
|
|
49894
|
+
confirm,
|
|
49895
|
+
getState: () => state,
|
|
49896
|
+
proposeSlotsForDay,
|
|
49897
|
+
reset,
|
|
49898
|
+
subscribe(listener) {
|
|
49899
|
+
listeners.add(listener);
|
|
49900
|
+
listener(state);
|
|
49901
|
+
return () => {
|
|
49902
|
+
listeners.delete(listener);
|
|
49903
|
+
};
|
|
49904
|
+
}
|
|
49905
|
+
};
|
|
49906
|
+
};
|
|
49907
|
+
// src/noShowPredictor.ts
|
|
49908
|
+
var clamp = (value, min = 0, max = 1) => Math.max(min, Math.min(max, value));
|
|
49909
|
+
var scoreVoiceNoShowRisk = (input) => {
|
|
49910
|
+
const now = input.now ?? (() => Date.now());
|
|
49911
|
+
const leadHours = (input.appointmentStartMs - input.bookedAtMs) / 3600000;
|
|
49912
|
+
const startDate = new Date(input.appointmentStartMs);
|
|
49913
|
+
const weekday = startDate.getUTCDay();
|
|
49914
|
+
const hour = startDate.getUTCHours();
|
|
49915
|
+
const history = input.history ?? [];
|
|
49916
|
+
const past = history.filter((r) => r.scheduledStartMs < input.appointmentStartMs);
|
|
49917
|
+
const priorNoShows = past.filter((r) => r.outcome === "no-show").length;
|
|
49918
|
+
const priorKept = past.filter((r) => r.outcome === "kept").length;
|
|
49919
|
+
let score = 0.15;
|
|
49920
|
+
const drivers = [];
|
|
49921
|
+
if (leadHours > 72) {
|
|
49922
|
+
score += 0.1;
|
|
49923
|
+
drivers.push({ kind: "lead-time-hours", value: leadHours });
|
|
49924
|
+
} else if (leadHours < 12) {
|
|
49925
|
+
score -= 0.05;
|
|
49926
|
+
drivers.push({ kind: "lead-time-hours", value: leadHours });
|
|
49927
|
+
}
|
|
49928
|
+
if (weekday === 1) {
|
|
49929
|
+
score += 0.04;
|
|
49930
|
+
drivers.push({ kind: "weekday", value: weekday });
|
|
49931
|
+
}
|
|
49932
|
+
if (weekday === 5) {
|
|
49933
|
+
score += 0.03;
|
|
49934
|
+
drivers.push({ kind: "weekday", value: weekday });
|
|
49935
|
+
}
|
|
49936
|
+
if (hour < 9 || hour >= 17) {
|
|
49937
|
+
score += 0.04;
|
|
49938
|
+
drivers.push({ kind: "hour-of-day", value: hour });
|
|
49939
|
+
}
|
|
49940
|
+
if (priorNoShows > 0) {
|
|
49941
|
+
const delta = Math.min(0.5, priorNoShows * 0.2);
|
|
49942
|
+
score += delta;
|
|
49943
|
+
drivers.push({ kind: "prior-no-show-count", value: priorNoShows });
|
|
49944
|
+
}
|
|
49945
|
+
if (priorKept > 2 && priorNoShows === 0) {
|
|
49946
|
+
score -= 0.08;
|
|
49947
|
+
drivers.push({ kind: "prior-kept-count", value: priorKept });
|
|
49948
|
+
}
|
|
49949
|
+
if (input.reminderConfirmed === true) {
|
|
49950
|
+
score -= 0.15;
|
|
49951
|
+
drivers.push({ kind: "reminder-confirmed", value: true });
|
|
49952
|
+
} else if (input.reminderConfirmed === false) {
|
|
49953
|
+
score += 0.1;
|
|
49954
|
+
drivers.push({ kind: "reminder-confirmed", value: false });
|
|
49955
|
+
}
|
|
49956
|
+
if (input.callbackDistanceHours !== undefined && input.callbackDistanceHours > 24) {
|
|
49957
|
+
score += 0.06;
|
|
49958
|
+
drivers.push({
|
|
49959
|
+
kind: "callback-distance-hours",
|
|
49960
|
+
value: input.callbackDistanceHours
|
|
49961
|
+
});
|
|
49962
|
+
}
|
|
49963
|
+
if (input.weatherDisruption) {
|
|
49964
|
+
score += 0.18;
|
|
49965
|
+
drivers.push({ kind: "weather-disruption", value: true });
|
|
49966
|
+
}
|
|
49967
|
+
const finalScore = clamp(score);
|
|
49968
|
+
const band = finalScore >= 0.55 ? "high" : finalScore >= 0.3 ? "moderate" : "low";
|
|
49969
|
+
return { band, drivers, score: finalScore };
|
|
49970
|
+
};
|
|
49971
|
+
var summarizeVoiceNoShowVerdict = (verdict) => {
|
|
49972
|
+
const pct = Math.round(verdict.score * 100);
|
|
49973
|
+
const top = verdict.drivers.slice(0, 2).map((d) => d.kind).join(", ");
|
|
49974
|
+
return `${verdict.band} risk (${pct}%)${top ? ` \u2014 driven by ${top}` : ""}`;
|
|
49975
|
+
};
|
|
49976
|
+
// src/reminderScheduler.ts
|
|
49977
|
+
var DEFAULT_VOICE_REMINDER_TRIGGERS = [
|
|
49978
|
+
{
|
|
49979
|
+
channel: "sms",
|
|
49980
|
+
id: "remind-24h",
|
|
49981
|
+
offsetMinutesBeforeStart: 24 * 60
|
|
49982
|
+
},
|
|
49983
|
+
{
|
|
49984
|
+
channel: "sms",
|
|
49985
|
+
id: "remind-2h",
|
|
49986
|
+
offsetMinutesBeforeStart: 120
|
|
49987
|
+
},
|
|
49988
|
+
{
|
|
49989
|
+
channel: "call",
|
|
49990
|
+
id: "remind-call-30m",
|
|
49991
|
+
offsetMinutesBeforeStart: 30,
|
|
49992
|
+
retryOnFailure: true
|
|
49993
|
+
}
|
|
49994
|
+
];
|
|
49995
|
+
var createVoiceReminderScheduler = (options = {}) => {
|
|
49996
|
+
const now = options.now ?? (() => Date.now());
|
|
49997
|
+
const generateId = options.generateJobId ?? (() => `rem_${Math.random().toString(36).slice(2, 10)}`);
|
|
49998
|
+
const defaultTriggers = options.defaultTriggers ?? DEFAULT_VOICE_REMINDER_TRIGGERS;
|
|
49999
|
+
const maxAttempts = options.maxAttempts ?? 2;
|
|
50000
|
+
const jobs = new Map;
|
|
50001
|
+
const listeners = new Set;
|
|
50002
|
+
const broadcast = (job) => {
|
|
50003
|
+
for (const listener of listeners)
|
|
50004
|
+
listener(job);
|
|
50005
|
+
};
|
|
50006
|
+
const schedule = (input) => {
|
|
50007
|
+
const triggers = input.triggers.length > 0 ? input.triggers : defaultTriggers;
|
|
50008
|
+
const at = now();
|
|
50009
|
+
const created = [];
|
|
50010
|
+
for (const trigger of triggers) {
|
|
50011
|
+
const fireAt = input.appointmentStartMs - trigger.offsetMinutesBeforeStart * 60000;
|
|
50012
|
+
if (fireAt <= at)
|
|
50013
|
+
continue;
|
|
50014
|
+
const job = {
|
|
50015
|
+
appointmentId: input.appointmentId,
|
|
50016
|
+
attempts: 0,
|
|
50017
|
+
channel: trigger.channel,
|
|
50018
|
+
id: generateId(),
|
|
50019
|
+
scheduledAtMs: fireAt,
|
|
50020
|
+
status: "pending",
|
|
50021
|
+
triggerId: trigger.id,
|
|
50022
|
+
...input.metadata !== undefined ? { metadata: input.metadata } : {}
|
|
50023
|
+
};
|
|
50024
|
+
jobs.set(job.id, job);
|
|
50025
|
+
created.push(job);
|
|
50026
|
+
broadcast(job);
|
|
50027
|
+
}
|
|
50028
|
+
return created;
|
|
50029
|
+
};
|
|
50030
|
+
const due = (at = now()) => Array.from(jobs.values()).filter((j) => j.status === "pending" && j.scheduledAtMs <= at);
|
|
50031
|
+
const markInFlight = (jobId) => {
|
|
50032
|
+
const job = jobs.get(jobId);
|
|
50033
|
+
if (!job || job.status !== "pending")
|
|
50034
|
+
return false;
|
|
50035
|
+
job.status = "in-flight";
|
|
50036
|
+
job.attempts += 1;
|
|
50037
|
+
broadcast(job);
|
|
50038
|
+
return true;
|
|
50039
|
+
};
|
|
50040
|
+
const markSent = (jobId) => {
|
|
50041
|
+
const job = jobs.get(jobId);
|
|
50042
|
+
if (!job)
|
|
50043
|
+
return false;
|
|
50044
|
+
job.status = "sent";
|
|
50045
|
+
broadcast(job);
|
|
50046
|
+
return true;
|
|
50047
|
+
};
|
|
50048
|
+
const markFailed = (jobId, error) => {
|
|
50049
|
+
const job = jobs.get(jobId);
|
|
50050
|
+
if (!job)
|
|
50051
|
+
return false;
|
|
50052
|
+
job.lastError = error;
|
|
50053
|
+
if (job.attempts < maxAttempts) {
|
|
50054
|
+
job.status = "pending";
|
|
50055
|
+
job.scheduledAtMs = now() + 5 * 60000;
|
|
50056
|
+
} else {
|
|
50057
|
+
job.status = "failed";
|
|
50058
|
+
}
|
|
50059
|
+
broadcast(job);
|
|
50060
|
+
return true;
|
|
50061
|
+
};
|
|
50062
|
+
const cancelForAppointment = (appointmentId) => {
|
|
50063
|
+
let count = 0;
|
|
50064
|
+
for (const job of jobs.values()) {
|
|
50065
|
+
if (job.appointmentId === appointmentId && (job.status === "pending" || job.status === "in-flight")) {
|
|
50066
|
+
job.status = "cancelled";
|
|
50067
|
+
broadcast(job);
|
|
50068
|
+
count += 1;
|
|
50069
|
+
}
|
|
50070
|
+
}
|
|
50071
|
+
return count;
|
|
50072
|
+
};
|
|
50073
|
+
return {
|
|
50074
|
+
cancelForAppointment,
|
|
50075
|
+
due,
|
|
50076
|
+
list: (appointmentId) => Array.from(jobs.values()).filter((j) => !appointmentId || j.appointmentId === appointmentId),
|
|
50077
|
+
markFailed,
|
|
50078
|
+
markInFlight,
|
|
50079
|
+
markSent,
|
|
50080
|
+
schedule,
|
|
50081
|
+
subscribe(listener) {
|
|
50082
|
+
listeners.add(listener);
|
|
50083
|
+
return () => {
|
|
50084
|
+
listeners.delete(listener);
|
|
50085
|
+
};
|
|
50086
|
+
}
|
|
50087
|
+
};
|
|
50088
|
+
};
|
|
49605
50089
|
export {
|
|
49606
50090
|
writeVoiceProofPack,
|
|
49607
50091
|
writeVoiceMediaPipelineArtifacts,
|
|
@@ -49649,6 +50133,7 @@ export {
|
|
|
49649
50133
|
summarizeVoiceOpsTaskQueue,
|
|
49650
50134
|
summarizeVoiceOpsTaskAnalytics,
|
|
49651
50135
|
summarizeVoiceOpsStatus,
|
|
50136
|
+
summarizeVoiceNoShowVerdict,
|
|
49652
50137
|
summarizeVoiceMediaPipelineReport,
|
|
49653
50138
|
summarizeVoiceLiveLatency,
|
|
49654
50139
|
summarizeVoiceIntegrationEvents,
|
|
@@ -49657,6 +50142,7 @@ export {
|
|
|
49657
50142
|
summarizeVoiceCampaigns,
|
|
49658
50143
|
summarizeVoiceCampaignDispositions,
|
|
49659
50144
|
summarizeVoiceCallerTranscript,
|
|
50145
|
+
summarizeVoiceCalendarSlot,
|
|
49660
50146
|
summarizeVoiceBrowserMedia,
|
|
49661
50147
|
summarizeVoiceBargeIn,
|
|
49662
50148
|
summarizeVoiceAuditTrail,
|
|
@@ -49670,6 +50156,7 @@ export {
|
|
|
49670
50156
|
shouldRetryCampaignAttempt,
|
|
49671
50157
|
shapeTelephonyAssistantText,
|
|
49672
50158
|
selectVoiceTraceEventsForPrune,
|
|
50159
|
+
scoreVoiceNoShowRisk,
|
|
49673
50160
|
saveVoiceIncidentBundleArtifact,
|
|
49674
50161
|
runVoiceToolContractSuite,
|
|
49675
50162
|
runVoiceToolContract,
|
|
@@ -49877,6 +50364,7 @@ export {
|
|
|
49877
50364
|
getLatestVoiceTelephonyMediaReport,
|
|
49878
50365
|
getLatestVoiceBrowserMediaReport,
|
|
49879
50366
|
getDefaultVoiceTelephonyBenchmarkScenarios,
|
|
50367
|
+
generateVoiceCalendarSlots,
|
|
49880
50368
|
fromVapiAssistantConfig,
|
|
49881
50369
|
formatVoiceProofTrendAge,
|
|
49882
50370
|
formatVoiceCallPlayerTimestamp,
|
|
@@ -50053,6 +50541,7 @@ export {
|
|
|
50053
50541
|
createVoiceRetentionScheduler,
|
|
50054
50542
|
createVoiceResilienceRoutes,
|
|
50055
50543
|
createVoiceReplayTimelineHTMXRoute,
|
|
50544
|
+
createVoiceReminderScheduler,
|
|
50056
50545
|
createVoiceRedisTelnyxWebhookEventStore,
|
|
50057
50546
|
createVoiceRedisTelephonyWebhookIdempotencyStore,
|
|
50058
50547
|
createVoiceRedisTaskLeaseCoordinator,
|
|
@@ -50193,6 +50682,7 @@ export {
|
|
|
50193
50682
|
createVoiceIncidentBundleRoutes,
|
|
50194
50683
|
createVoiceInMemoryRealCallProfileRecoveryJobStore,
|
|
50195
50684
|
createVoiceInMemoryMonitorRegistry,
|
|
50685
|
+
createVoiceInMemoryCalendarAdapter,
|
|
50196
50686
|
createVoiceIVRSession,
|
|
50197
50687
|
createVoiceHubSpotTaskUpdateSink,
|
|
50198
50688
|
createVoiceHubSpotTaskSyncSinks,
|
|
@@ -50267,6 +50757,7 @@ export {
|
|
|
50267
50757
|
createVoiceCRMActivitySink,
|
|
50268
50758
|
createVoiceBrowserMediaRoutes,
|
|
50269
50759
|
createVoiceBrowserCallProfileRoutes,
|
|
50760
|
+
createVoiceBookingFlow,
|
|
50270
50761
|
createVoiceBearerAuthVerifier,
|
|
50271
50762
|
createVoiceBargeInRoutes,
|
|
50272
50763
|
createVoiceBackchannelDriver,
|
|
@@ -50494,6 +50985,7 @@ export {
|
|
|
50494
50985
|
VOICE_DTMF_DIGITS,
|
|
50495
50986
|
VOICE_CALLER_MEMORY_KEY,
|
|
50496
50987
|
TURN_PROFILE_DEFAULTS,
|
|
50988
|
+
DEFAULT_VOICE_REMINDER_TRIGGERS,
|
|
50497
50989
|
DEFAULT_VOICE_REDACTION_PATTERNS,
|
|
50498
50990
|
DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS,
|
|
50499
50991
|
DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type VoiceNoShowHistoricalRecord = {
|
|
2
|
+
appointmentId: string;
|
|
3
|
+
scheduledStartMs: number;
|
|
4
|
+
outcome: "kept" | "no-show" | "cancelled" | "rescheduled";
|
|
5
|
+
};
|
|
6
|
+
export type VoiceNoShowSignal = {
|
|
7
|
+
kind: "lead-time-hours";
|
|
8
|
+
value: number;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "weekday";
|
|
11
|
+
value: number;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "hour-of-day";
|
|
14
|
+
value: number;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "prior-no-show-count";
|
|
17
|
+
value: number;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "prior-kept-count";
|
|
20
|
+
value: number;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "reminder-confirmed";
|
|
23
|
+
value: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "callback-distance-hours";
|
|
26
|
+
value: number;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "weather-disruption";
|
|
29
|
+
value: boolean;
|
|
30
|
+
};
|
|
31
|
+
export type VoiceNoShowScoreInput = {
|
|
32
|
+
appointmentStartMs: number;
|
|
33
|
+
bookedAtMs: number;
|
|
34
|
+
history?: VoiceNoShowHistoricalRecord[];
|
|
35
|
+
reminderConfirmed?: boolean;
|
|
36
|
+
weatherDisruption?: boolean;
|
|
37
|
+
callbackDistanceHours?: number;
|
|
38
|
+
now?: () => number;
|
|
39
|
+
};
|
|
40
|
+
export type VoiceNoShowVerdict = {
|
|
41
|
+
score: number;
|
|
42
|
+
band: "low" | "moderate" | "high";
|
|
43
|
+
drivers: VoiceNoShowSignal[];
|
|
44
|
+
};
|
|
45
|
+
export declare const scoreVoiceNoShowRisk: (input: VoiceNoShowScoreInput) => VoiceNoShowVerdict;
|
|
46
|
+
export declare const summarizeVoiceNoShowVerdict: (verdict: VoiceNoShowVerdict) => string;
|
package/dist/react/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type VoiceReminderChannel = "call" | "sms" | "email";
|
|
2
|
+
export type VoiceReminderTrigger = {
|
|
3
|
+
id: string;
|
|
4
|
+
channel: VoiceReminderChannel;
|
|
5
|
+
offsetMinutesBeforeStart: number;
|
|
6
|
+
templateId?: string;
|
|
7
|
+
retryOnFailure?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type VoiceReminderJob = {
|
|
10
|
+
id: string;
|
|
11
|
+
appointmentId: string;
|
|
12
|
+
triggerId: string;
|
|
13
|
+
channel: VoiceReminderChannel;
|
|
14
|
+
scheduledAtMs: number;
|
|
15
|
+
status: "pending" | "in-flight" | "sent" | "skipped" | "failed" | "cancelled";
|
|
16
|
+
attempts: number;
|
|
17
|
+
lastError?: string;
|
|
18
|
+
metadata?: Record<string, string>;
|
|
19
|
+
};
|
|
20
|
+
export type ScheduleVoiceRemindersInput = {
|
|
21
|
+
appointmentId: string;
|
|
22
|
+
appointmentStartMs: number;
|
|
23
|
+
triggers: VoiceReminderTrigger[];
|
|
24
|
+
metadata?: Record<string, string>;
|
|
25
|
+
};
|
|
26
|
+
export type CreateVoiceReminderSchedulerOptions = {
|
|
27
|
+
generateJobId?: () => string;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
defaultTriggers?: VoiceReminderTrigger[];
|
|
30
|
+
maxAttempts?: number;
|
|
31
|
+
};
|
|
32
|
+
export declare const DEFAULT_VOICE_REMINDER_TRIGGERS: VoiceReminderTrigger[];
|
|
33
|
+
export declare const createVoiceReminderScheduler: (options?: CreateVoiceReminderSchedulerOptions) => {
|
|
34
|
+
cancelForAppointment: (appointmentId: string) => number;
|
|
35
|
+
due: (at?: number) => VoiceReminderJob[];
|
|
36
|
+
list: (appointmentId?: string) => VoiceReminderJob[];
|
|
37
|
+
markFailed: (jobId: string, error: string) => boolean;
|
|
38
|
+
markInFlight: (jobId: string) => boolean;
|
|
39
|
+
markSent: (jobId: string) => boolean;
|
|
40
|
+
schedule: (input: ScheduleVoiceRemindersInput) => VoiceReminderJob[];
|
|
41
|
+
subscribe(listener: (job: VoiceReminderJob) => void): () => void;
|
|
42
|
+
};
|
|
43
|
+
export type VoiceReminderScheduler = ReturnType<typeof createVoiceReminderScheduler>;
|
package/dist/svelte/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|
package/dist/testing/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|
package/dist/vue/index.js
CHANGED
|
@@ -10,6 +10,19 @@ var __name = (target, name) => {
|
|
|
10
10
|
});
|
|
11
11
|
return target;
|
|
12
12
|
};
|
|
13
|
+
var __returnValue = (v) => v;
|
|
14
|
+
function __exportSetter(name, newValue) {
|
|
15
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
16
|
+
}
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
set: __exportSetter.bind(all, name)
|
|
24
|
+
});
|
|
25
|
+
};
|
|
13
26
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
14
27
|
var __typeError = (msg) => {
|
|
15
28
|
throw TypeError(msg);
|