@peektravel/app-utilities 0.2.4 → 0.2.6
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/index.cjs +49 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +212 -23
- package/dist/index.d.ts +212 -23
- package/dist/index.js +49 -25
- package/dist/index.js.map +1 -1
- package/dist/ui/index.cjs +142 -14
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +30 -3
- package/dist/ui/index.d.ts +30 -3
- package/dist/ui/index.js +142 -14
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -266,7 +266,7 @@ function fromBookingNode(node, includeGuests = false, includePriceBreakdown = fa
|
|
|
266
266
|
timeslotId: data.timeSnapshot?.legacyId || null,
|
|
267
267
|
totalTickets: ticketQuantity(ticketQuantities),
|
|
268
268
|
ticketDescription: formatTickets(ticketQuantities),
|
|
269
|
-
tickets: ticketsToTicketArray(ticketQuantities),
|
|
269
|
+
tickets: ticketsToTicketArray(ticketQuantities, includePriceBreakdown),
|
|
270
270
|
isCanceled: data.reservationStatus === "CANCELED",
|
|
271
271
|
isNoShow: data.fulfillmentStatusOverride?.status === "NO_SHOW",
|
|
272
272
|
isCheckedIn: data.checkinStatus !== "NONE",
|
|
@@ -367,12 +367,14 @@ function resellerNameFromChannelSnapshot(channelSnapshot) {
|
|
|
367
367
|
}
|
|
368
368
|
return out;
|
|
369
369
|
}
|
|
370
|
-
function ticketsToTicketArray(ticketQuantities) {
|
|
370
|
+
function ticketsToTicketArray(ticketQuantities, includePriceBreakdown) {
|
|
371
371
|
if (!ticketQuantities || ticketQuantities.length === 0) return [];
|
|
372
372
|
return ticketQuantities.map((ticket) => ({
|
|
373
373
|
name: ticket.resourceOptionSnapshot?.name || "Unknown",
|
|
374
374
|
quantity: ticket.quantity || 0,
|
|
375
|
-
ticketId: ticket.resourceOptionSnapshot?.id || "unknown"
|
|
375
|
+
ticketId: ticket.resourceOptionSnapshot?.id || "unknown",
|
|
376
|
+
listPrice: includePriceBreakdown ? mapPrice(ticket.value?.price) : void 0,
|
|
377
|
+
totalValue: includePriceBreakdown ? mapPrice(ticket.value?.total) : void 0
|
|
376
378
|
}));
|
|
377
379
|
}
|
|
378
380
|
function durationInMin(startsAt, endsAt) {
|
|
@@ -737,9 +739,15 @@ var PRICE_BREAKDOWN_FIELDS = `
|
|
|
737
739
|
taxes { amount formatted }
|
|
738
740
|
tips { amount formatted }
|
|
739
741
|
`;
|
|
742
|
+
var TICKET_VALUE_FIELDS = `
|
|
743
|
+
value {
|
|
744
|
+
price { amount formatted }
|
|
745
|
+
total { amount formatted }
|
|
746
|
+
}
|
|
747
|
+
`;
|
|
740
748
|
function buildBookingsListingQuery(includeGuests, includePriceBreakdown) {
|
|
741
749
|
const guestsSection = includeGuests ? bookingGuestsFields : "";
|
|
742
|
-
const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`) : bookingQueryFields;
|
|
750
|
+
const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`).replace("ticketQuantities {", `ticketQuantities { ${TICKET_VALUE_FIELDS}`) : bookingQueryFields;
|
|
743
751
|
return `
|
|
744
752
|
query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
|
|
745
753
|
sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
|
|
@@ -934,14 +942,18 @@ function buildBookingsVariables(params) {
|
|
|
934
942
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
935
943
|
var DEFAULT_CANCEL_NOTE = "Canceled";
|
|
936
944
|
var DEFAULT_CUSTOMER_MESSAGE = "Charge initiated via API";
|
|
937
|
-
var
|
|
945
|
+
var BOOKING_DB_ID_REGEX = /^b_[a-z0-9]+$/;
|
|
946
|
+
var BOOKING_DISPLAY_ID_REGEX = /^B-[A-Z0-9]+$/;
|
|
947
|
+
var ORDER_DB_ID_REGEX = /^o_[a-z0-9]+$/;
|
|
948
|
+
var ORDER_DISPLAY_ID_REGEX = /^O-[A-Z0-9]+$/;
|
|
938
949
|
var PAYMENT_SOURCE_PREFIX = "ps_";
|
|
939
950
|
var PAYMENT_ID_PREFIX = "pmt_";
|
|
940
951
|
var ALLOWED_PAYMENT_SOURCE_IDS = ["cash/cash", "custom/other", "custom/voucher"];
|
|
941
952
|
var CURRENCY_CODE_REGEX = /^[A-Z]{3}$/;
|
|
942
953
|
var ERROR_ADDON_OPTION_ID_REQUIRED = "addonOptionId is required";
|
|
943
954
|
var ERROR_QUANTITY_INVALID = "quantity must be a positive integer string";
|
|
944
|
-
var
|
|
955
|
+
var ERROR_INVALID_BOOKING_ID = "bookingId is required and must be a valid booking id, e.g. 'b_abc123' or 'B-ABC123'";
|
|
956
|
+
var ERROR_INVALID_ORDER_ID = "orderId is required and must be a valid order id, e.g. 'o_abc123' or 'O-ABC123'";
|
|
945
957
|
var ERROR_BOOKING_NOT_FOUND = "Booking not found";
|
|
946
958
|
var ERROR_MULTIPLE_BOOKINGS_FOUND = "Expected exactly one booking for the provided bookingId";
|
|
947
959
|
var ERROR_NO_ADDON_OPTION_TO_REMOVE = "No confirmed add-on option matching addonOptionId was found on the booking";
|
|
@@ -973,6 +985,7 @@ var BookingService = class {
|
|
|
973
985
|
* ```
|
|
974
986
|
*/
|
|
975
987
|
async getById(bookingId, options = {}) {
|
|
988
|
+
assertBookingId(bookingId);
|
|
976
989
|
const includeGuests = options.includeGuests ?? false;
|
|
977
990
|
const includePriceBreakdown = options.includePriceBreakdown ?? false;
|
|
978
991
|
const body = await this.client.request(
|
|
@@ -1021,6 +1034,7 @@ var BookingService = class {
|
|
|
1021
1034
|
}
|
|
1022
1035
|
/** Returns the guests on a booking (primary guest included). */
|
|
1023
1036
|
async getGuests(bookingId) {
|
|
1037
|
+
assertBookingId(bookingId);
|
|
1024
1038
|
const body = await this.client.request(
|
|
1025
1039
|
SALES_ENDPOINT,
|
|
1026
1040
|
BOOKING_GUESTS_QUERY,
|
|
@@ -1034,6 +1048,7 @@ var BookingService = class {
|
|
|
1034
1048
|
}
|
|
1035
1049
|
/** Returns the payments on file for a booking, or null when not found. */
|
|
1036
1050
|
async getPaymentsOnFile(bookingId) {
|
|
1051
|
+
assertBookingId(bookingId);
|
|
1037
1052
|
const normalized = normalizeBookingId(bookingId);
|
|
1038
1053
|
const body = await this.client.request(
|
|
1039
1054
|
SALES_ENDPOINT,
|
|
@@ -1047,6 +1062,7 @@ var BookingService = class {
|
|
|
1047
1062
|
* booking, or null when the booking is not found.
|
|
1048
1063
|
*/
|
|
1049
1064
|
async appendNote(bookingId, note, mode = "append") {
|
|
1065
|
+
assertBookingId(bookingId);
|
|
1050
1066
|
const normalized = normalizeBookingId(bookingId);
|
|
1051
1067
|
const booking = await this.getById(normalized);
|
|
1052
1068
|
if (!booking) {
|
|
@@ -1065,6 +1081,7 @@ ${note}`;
|
|
|
1065
1081
|
* when not found.
|
|
1066
1082
|
*/
|
|
1067
1083
|
async setCheckinStatus(bookingId, checkedIn) {
|
|
1084
|
+
assertBookingId(bookingId);
|
|
1068
1085
|
const normalized = normalizeBookingId(bookingId);
|
|
1069
1086
|
const checkedInAt = checkedIn ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
1070
1087
|
await this.client.request(SALES_ENDPOINT, UPDATE_BOOKING_CHECKIN_MUTATION, {
|
|
@@ -1074,6 +1091,7 @@ ${note}`;
|
|
|
1074
1091
|
}
|
|
1075
1092
|
/** Cancels a booking and returns its id/displayId/status. */
|
|
1076
1093
|
async cancel(bookingId, notes = DEFAULT_CANCEL_NOTE) {
|
|
1094
|
+
assertBookingId(bookingId);
|
|
1077
1095
|
const body = await this.client.request(
|
|
1078
1096
|
SALES_ENDPOINT,
|
|
1079
1097
|
CANCEL_BOOKING_MUTATION,
|
|
@@ -1109,12 +1127,13 @@ ${note}`;
|
|
|
1109
1127
|
* @throws {Error} when `paymentSourceId` is missing or not a `ps_…` id / one
|
|
1110
1128
|
* of `cash/cash`, `custom/other`, `custom/voucher`; when `amount` is not a
|
|
1111
1129
|
* valid number; when `currency` is not a 3-letter uppercase code; when
|
|
1112
|
-
* `idempotencyKey` is empty; when `bookingId`
|
|
1113
|
-
* when the booking or payment source is not found; or when the
|
|
1130
|
+
* `idempotencyKey` is empty; when `bookingId` is not a valid booking id
|
|
1131
|
+
* (`b_…`/`B-…`); when the booking or payment source is not found; or when the
|
|
1132
|
+
* charge fails.
|
|
1114
1133
|
*/
|
|
1115
1134
|
async makePayment(input) {
|
|
1135
|
+
this.validatePaymentInput(input);
|
|
1116
1136
|
const normalized = normalizeBookingId(input.bookingId);
|
|
1117
|
-
this.validatePaymentInput(input, normalized);
|
|
1118
1137
|
const onFile = await this.getPaymentsOnFile(normalized);
|
|
1119
1138
|
if (!onFile) {
|
|
1120
1139
|
throw new Error("Booking not found");
|
|
@@ -1155,8 +1174,8 @@ ${note}`;
|
|
|
1155
1174
|
* payments-on-file, then applies the refund.
|
|
1156
1175
|
*/
|
|
1157
1176
|
async refund(input) {
|
|
1177
|
+
this.validateRefundInput(input);
|
|
1158
1178
|
const normalized = normalizeBookingId(input.bookingId);
|
|
1159
|
-
this.validateRefundInput(input, normalized);
|
|
1160
1179
|
const onFile = await this.getPaymentsOnFile(normalized);
|
|
1161
1180
|
if (!onFile) {
|
|
1162
1181
|
throw new Error("Booking not found");
|
|
@@ -1195,9 +1214,7 @@ ${note}`;
|
|
|
1195
1214
|
}
|
|
1196
1215
|
/** Creates an invoice link for a booking's order. */
|
|
1197
1216
|
async createInvoiceLink(bookingId) {
|
|
1198
|
-
|
|
1199
|
-
throw new Error("bookingId is required");
|
|
1200
|
-
}
|
|
1217
|
+
assertBookingId(bookingId);
|
|
1201
1218
|
const normalized = normalizeBookingId(bookingId);
|
|
1202
1219
|
const booking = await this.getById(normalized);
|
|
1203
1220
|
if (!booking || !booking.orderId) {
|
|
@@ -1217,6 +1234,7 @@ ${note}`;
|
|
|
1217
1234
|
}
|
|
1218
1235
|
/** Returns the add-ons on a booking, grouped by add-on item (clean model). */
|
|
1219
1236
|
async listAddons(bookingId) {
|
|
1237
|
+
assertBookingId(bookingId);
|
|
1220
1238
|
const { items, displayId, orderId, normalizedBookingId } = await this.fetchBookingSale(bookingId);
|
|
1221
1239
|
const addons = items.map((item) => toBookingAddon(item)).filter((addon) => addon !== null);
|
|
1222
1240
|
return {
|
|
@@ -1251,6 +1269,7 @@ ${note}`;
|
|
|
1251
1269
|
* the underlying quote/order mutations fail.
|
|
1252
1270
|
*/
|
|
1253
1271
|
async addAddon(bookingId, input) {
|
|
1272
|
+
assertBookingId(bookingId);
|
|
1254
1273
|
const addonOptionId = (input?.addonOptionId || input?.addonId || "").trim();
|
|
1255
1274
|
if (!addonOptionId) {
|
|
1256
1275
|
throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);
|
|
@@ -1303,6 +1322,7 @@ ${note}`;
|
|
|
1303
1322
|
* variables. Returns the booking's add-ons after the change.
|
|
1304
1323
|
*/
|
|
1305
1324
|
async removeAddon(bookingId, input) {
|
|
1325
|
+
assertBookingId(bookingId);
|
|
1306
1326
|
const addonOptionId = (input?.addonOptionId || input?.addonId || "").trim();
|
|
1307
1327
|
if (!addonOptionId) {
|
|
1308
1328
|
throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);
|
|
@@ -1331,14 +1351,10 @@ ${note}`;
|
|
|
1331
1351
|
* booking matched, and parses the node into the internal model.
|
|
1332
1352
|
*/
|
|
1333
1353
|
async fetchBookingSale(bookingId) {
|
|
1334
|
-
const searchString = (bookingId || "").trim();
|
|
1335
|
-
if (!searchString) {
|
|
1336
|
-
throw new Error(ERROR_BOOKING_ID_REQUIRED);
|
|
1337
|
-
}
|
|
1338
1354
|
const body = await this.client.request(
|
|
1339
1355
|
SALES_ENDPOINT,
|
|
1340
1356
|
SALES_ADDONS_QUERY,
|
|
1341
|
-
buildSalesAddonsVariables(
|
|
1357
|
+
buildSalesAddonsVariables(bookingId)
|
|
1342
1358
|
);
|
|
1343
1359
|
const edges = body.data?.sales?.edges ?? [];
|
|
1344
1360
|
if (edges.length === 0) {
|
|
@@ -1521,7 +1537,7 @@ ${note}`;
|
|
|
1521
1537
|
}
|
|
1522
1538
|
return matched.productId;
|
|
1523
1539
|
}
|
|
1524
|
-
validatePaymentInput(input
|
|
1540
|
+
validatePaymentInput(input) {
|
|
1525
1541
|
if (!input.paymentSourceId || !input.paymentSourceId.startsWith(PAYMENT_SOURCE_PREFIX) && !ALLOWED_PAYMENT_SOURCE_IDS.includes(input.paymentSourceId)) {
|
|
1526
1542
|
throw new Error(
|
|
1527
1543
|
"paymentSourceId is required and must start with 'ps_' or be one of 'cash/cash', 'custom/other', 'custom/voucher'"
|
|
@@ -1530,16 +1546,16 @@ ${note}`;
|
|
|
1530
1546
|
assertAmount(input.amount);
|
|
1531
1547
|
assertCurrency(input.currency);
|
|
1532
1548
|
assertIdempotencyKey(input.idempotencyKey);
|
|
1533
|
-
assertBookingId(
|
|
1549
|
+
assertBookingId(input.bookingId);
|
|
1534
1550
|
}
|
|
1535
|
-
validateRefundInput(input
|
|
1551
|
+
validateRefundInput(input) {
|
|
1536
1552
|
if (!input.paymentId || !input.paymentId.startsWith(PAYMENT_ID_PREFIX)) {
|
|
1537
1553
|
throw new Error("paymentId is required and must start with 'pmt_'");
|
|
1538
1554
|
}
|
|
1539
1555
|
assertAmount(input.amount);
|
|
1540
1556
|
assertCurrency(input.currency);
|
|
1541
1557
|
assertIdempotencyKey(input.idempotencyKey);
|
|
1542
|
-
assertBookingId(
|
|
1558
|
+
assertBookingId(input.bookingId);
|
|
1543
1559
|
}
|
|
1544
1560
|
async fetchPaginated(query, baseParams, includeGuests, includePriceBreakdown) {
|
|
1545
1561
|
const bookings = [];
|
|
@@ -1579,9 +1595,14 @@ function assertIdempotencyKey(idempotencyKey) {
|
|
|
1579
1595
|
throw new Error("idempotencyKey is required");
|
|
1580
1596
|
}
|
|
1581
1597
|
}
|
|
1582
|
-
function assertBookingId(
|
|
1583
|
-
if (!
|
|
1584
|
-
throw new Error(
|
|
1598
|
+
function assertBookingId(bookingId) {
|
|
1599
|
+
if (!(BOOKING_DB_ID_REGEX.test(bookingId) || BOOKING_DISPLAY_ID_REGEX.test(bookingId))) {
|
|
1600
|
+
throw new Error(ERROR_INVALID_BOOKING_ID);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
function assertOrderId(orderId) {
|
|
1604
|
+
if (!(ORDER_DB_ID_REGEX.test(orderId) || ORDER_DISPLAY_ID_REGEX.test(orderId))) {
|
|
1605
|
+
throw new Error(ERROR_INVALID_ORDER_ID);
|
|
1585
1606
|
}
|
|
1586
1607
|
}
|
|
1587
1608
|
function validateCreateInput(input) {
|
|
@@ -1599,6 +1620,9 @@ function validateCreateInput(input) {
|
|
|
1599
1620
|
if (input.markAsPaid && !input.idempotencyKey) {
|
|
1600
1621
|
throw new Error("idempotencyKey is required when markAsPaid is set");
|
|
1601
1622
|
}
|
|
1623
|
+
if (input.parentOrderId) {
|
|
1624
|
+
assertOrderId(input.parentOrderId);
|
|
1625
|
+
}
|
|
1602
1626
|
}
|
|
1603
1627
|
function parseQuantity(value) {
|
|
1604
1628
|
if (typeof value !== "string" && typeof value !== "number") {
|