1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { set } from "https://esm.town/v/vtdocs/set";
import { resyBookSlot } from "https://esm.town/v/vtdocs/resyBookSlot";
import { resyGetSlotBookingToken } from "https://esm.town/v/vtdocs/resyGetSlotBookingToken";
import { resyGetMatchingSlot } from "https://esm.town/v/vtdocs/resyGetMatchingSlot";
import { resyVenueIdFromSlugAndCity } from "https://esm.town/v/vtdocs/resyVenueIdFromSlugAndCity";
import { resyAuth } from "https://esm.town/v/vtdocs/resyAuth";
let { resyBotData } = await import("https://esm.town/v/vtdocs/resyBotData");
import { sha256 } from "https://esm.town/v/vtdocs/sha256";
export const resyBot = async (opts: {
slug: string; // amaro-bar
city: string; // ldn
day: string; // 2023-07-05
start: string; // 19:00
end: string; // 21:00
partySize: number; // 2
email: string; // resy email
password: string;
}): Promise<string> => {
const { slug, city, day, start, end, partySize, email, password } = opts;
// Avoid duplicate bookings by looking for a successful booking for the current parameters
const key = [
slug,
city,
day,
start,
end,
partySize,
await sha256(email),
].join(",");
if (resyBotData === undefined) {
resyBotData = {};
}
if (resyBotData[key] !== undefined) {
throw new Error(
`not running resy bot – successful booking exists for ${key}`,
);
}
const auth = await resyAuth(email, password);
const venue = await resyVenueIdFromSlugAndCity(
auth.token,
slug,
city,
);
// If there are no matching slots, an error is thrown
const matchingSlot = await resyGetMatchingSlot(
auth.token,
venue.id,
day,
start,
end,
partySize,
);
// At this point, there's a bookable slot (but it could still be sniped from us!)
const { bookToken } = await resyGetSlotBookingToken(
auth.token,
matchingSlot.config.token,
matchingSlot.date.start,
partySize,
);
if (auth.paymentMethods.length === 0) {
throw new Error("no payment methods on account (add one and try again)");
}
const bookingMetadata = await resyBookSlot(
auth.token,
bookToken,
auth.paymentMethods[0].id,
);
// Store successful booking to avoid duplicate bookings
resyBotData[key] = bookingMetadata;
await set("resyBotData", resyBotData);
return `Booked ${slug} in ${city} at ${matchingSlot.date.start} for ${partySize} people.
Check https://resy.com/account/reservations-and-notify for more details!`;
};