@peektravel/app-utilities 0.2.5 → 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 +39 -8
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +9 -3
- package/dist/ui/index.d.ts +9 -3
- package/dist/ui/index.js +39 -8
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -288,7 +288,7 @@ function fromBookingNode(node, includeGuests = false, includePriceBreakdown = fa
|
|
|
288
288
|
timeslotId: data.timeSnapshot?.legacyId || null,
|
|
289
289
|
totalTickets: ticketQuantity(ticketQuantities),
|
|
290
290
|
ticketDescription: formatTickets(ticketQuantities),
|
|
291
|
-
tickets: ticketsToTicketArray(ticketQuantities),
|
|
291
|
+
tickets: ticketsToTicketArray(ticketQuantities, includePriceBreakdown),
|
|
292
292
|
isCanceled: data.reservationStatus === "CANCELED",
|
|
293
293
|
isNoShow: data.fulfillmentStatusOverride?.status === "NO_SHOW",
|
|
294
294
|
isCheckedIn: data.checkinStatus !== "NONE",
|
|
@@ -389,12 +389,14 @@ function resellerNameFromChannelSnapshot(channelSnapshot) {
|
|
|
389
389
|
}
|
|
390
390
|
return out;
|
|
391
391
|
}
|
|
392
|
-
function ticketsToTicketArray(ticketQuantities) {
|
|
392
|
+
function ticketsToTicketArray(ticketQuantities, includePriceBreakdown) {
|
|
393
393
|
if (!ticketQuantities || ticketQuantities.length === 0) return [];
|
|
394
394
|
return ticketQuantities.map((ticket) => ({
|
|
395
395
|
name: ticket.resourceOptionSnapshot?.name || "Unknown",
|
|
396
396
|
quantity: ticket.quantity || 0,
|
|
397
|
-
ticketId: ticket.resourceOptionSnapshot?.id || "unknown"
|
|
397
|
+
ticketId: ticket.resourceOptionSnapshot?.id || "unknown",
|
|
398
|
+
listPrice: includePriceBreakdown ? mapPrice(ticket.value?.price) : void 0,
|
|
399
|
+
totalValue: includePriceBreakdown ? mapPrice(ticket.value?.total) : void 0
|
|
398
400
|
}));
|
|
399
401
|
}
|
|
400
402
|
function durationInMin(startsAt, endsAt) {
|
|
@@ -759,9 +761,15 @@ var PRICE_BREAKDOWN_FIELDS = `
|
|
|
759
761
|
taxes { amount formatted }
|
|
760
762
|
tips { amount formatted }
|
|
761
763
|
`;
|
|
764
|
+
var TICKET_VALUE_FIELDS = `
|
|
765
|
+
value {
|
|
766
|
+
price { amount formatted }
|
|
767
|
+
total { amount formatted }
|
|
768
|
+
}
|
|
769
|
+
`;
|
|
762
770
|
function buildBookingsListingQuery(includeGuests, includePriceBreakdown) {
|
|
763
771
|
const guestsSection = includeGuests ? bookingGuestsFields : "";
|
|
764
|
-
const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`) : bookingQueryFields;
|
|
772
|
+
const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`).replace("ticketQuantities {", `ticketQuantities { ${TICKET_VALUE_FIELDS}`) : bookingQueryFields;
|
|
765
773
|
return `
|
|
766
774
|
query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
|
|
767
775
|
sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
|
|
@@ -956,14 +964,18 @@ function buildBookingsVariables(params) {
|
|
|
956
964
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
957
965
|
var DEFAULT_CANCEL_NOTE = "Canceled";
|
|
958
966
|
var DEFAULT_CUSTOMER_MESSAGE = "Charge initiated via API";
|
|
959
|
-
var
|
|
967
|
+
var BOOKING_DB_ID_REGEX = /^b_[a-z0-9]+$/;
|
|
968
|
+
var BOOKING_DISPLAY_ID_REGEX = /^B-[A-Z0-9]+$/;
|
|
969
|
+
var ORDER_DB_ID_REGEX = /^o_[a-z0-9]+$/;
|
|
970
|
+
var ORDER_DISPLAY_ID_REGEX = /^O-[A-Z0-9]+$/;
|
|
960
971
|
var PAYMENT_SOURCE_PREFIX = "ps_";
|
|
961
972
|
var PAYMENT_ID_PREFIX = "pmt_";
|
|
962
973
|
var ALLOWED_PAYMENT_SOURCE_IDS = ["cash/cash", "custom/other", "custom/voucher"];
|
|
963
974
|
var CURRENCY_CODE_REGEX = /^[A-Z]{3}$/;
|
|
964
975
|
var ERROR_ADDON_OPTION_ID_REQUIRED = "addonOptionId is required";
|
|
965
976
|
var ERROR_QUANTITY_INVALID = "quantity must be a positive integer string";
|
|
966
|
-
var
|
|
977
|
+
var ERROR_INVALID_BOOKING_ID = "bookingId is required and must be a valid booking id, e.g. 'b_abc123' or 'B-ABC123'";
|
|
978
|
+
var ERROR_INVALID_ORDER_ID = "orderId is required and must be a valid order id, e.g. 'o_abc123' or 'O-ABC123'";
|
|
967
979
|
var ERROR_BOOKING_NOT_FOUND = "Booking not found";
|
|
968
980
|
var ERROR_MULTIPLE_BOOKINGS_FOUND = "Expected exactly one booking for the provided bookingId";
|
|
969
981
|
var ERROR_NO_ADDON_OPTION_TO_REMOVE = "No confirmed add-on option matching addonOptionId was found on the booking";
|
|
@@ -995,6 +1007,7 @@ var BookingService = class {
|
|
|
995
1007
|
* ```
|
|
996
1008
|
*/
|
|
997
1009
|
async getById(bookingId, options = {}) {
|
|
1010
|
+
assertBookingId(bookingId);
|
|
998
1011
|
const includeGuests = options.includeGuests ?? false;
|
|
999
1012
|
const includePriceBreakdown = options.includePriceBreakdown ?? false;
|
|
1000
1013
|
const body = await this.client.request(
|
|
@@ -1043,6 +1056,7 @@ var BookingService = class {
|
|
|
1043
1056
|
}
|
|
1044
1057
|
/** Returns the guests on a booking (primary guest included). */
|
|
1045
1058
|
async getGuests(bookingId) {
|
|
1059
|
+
assertBookingId(bookingId);
|
|
1046
1060
|
const body = await this.client.request(
|
|
1047
1061
|
SALES_ENDPOINT,
|
|
1048
1062
|
BOOKING_GUESTS_QUERY,
|
|
@@ -1056,6 +1070,7 @@ var BookingService = class {
|
|
|
1056
1070
|
}
|
|
1057
1071
|
/** Returns the payments on file for a booking, or null when not found. */
|
|
1058
1072
|
async getPaymentsOnFile(bookingId) {
|
|
1073
|
+
assertBookingId(bookingId);
|
|
1059
1074
|
const normalized = normalizeBookingId(bookingId);
|
|
1060
1075
|
const body = await this.client.request(
|
|
1061
1076
|
SALES_ENDPOINT,
|
|
@@ -1069,6 +1084,7 @@ var BookingService = class {
|
|
|
1069
1084
|
* booking, or null when the booking is not found.
|
|
1070
1085
|
*/
|
|
1071
1086
|
async appendNote(bookingId, note, mode = "append") {
|
|
1087
|
+
assertBookingId(bookingId);
|
|
1072
1088
|
const normalized = normalizeBookingId(bookingId);
|
|
1073
1089
|
const booking = await this.getById(normalized);
|
|
1074
1090
|
if (!booking) {
|
|
@@ -1087,6 +1103,7 @@ ${note}`;
|
|
|
1087
1103
|
* when not found.
|
|
1088
1104
|
*/
|
|
1089
1105
|
async setCheckinStatus(bookingId, checkedIn) {
|
|
1106
|
+
assertBookingId(bookingId);
|
|
1090
1107
|
const normalized = normalizeBookingId(bookingId);
|
|
1091
1108
|
const checkedInAt = checkedIn ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
1092
1109
|
await this.client.request(SALES_ENDPOINT, UPDATE_BOOKING_CHECKIN_MUTATION, {
|
|
@@ -1096,6 +1113,7 @@ ${note}`;
|
|
|
1096
1113
|
}
|
|
1097
1114
|
/** Cancels a booking and returns its id/displayId/status. */
|
|
1098
1115
|
async cancel(bookingId, notes = DEFAULT_CANCEL_NOTE) {
|
|
1116
|
+
assertBookingId(bookingId);
|
|
1099
1117
|
const body = await this.client.request(
|
|
1100
1118
|
SALES_ENDPOINT,
|
|
1101
1119
|
CANCEL_BOOKING_MUTATION,
|
|
@@ -1131,12 +1149,13 @@ ${note}`;
|
|
|
1131
1149
|
* @throws {Error} when `paymentSourceId` is missing or not a `ps_…` id / one
|
|
1132
1150
|
* of `cash/cash`, `custom/other`, `custom/voucher`; when `amount` is not a
|
|
1133
1151
|
* valid number; when `currency` is not a 3-letter uppercase code; when
|
|
1134
|
-
* `idempotencyKey` is empty; when `bookingId`
|
|
1135
|
-
* when the booking or payment source is not found; or when the
|
|
1152
|
+
* `idempotencyKey` is empty; when `bookingId` is not a valid booking id
|
|
1153
|
+
* (`b_…`/`B-…`); when the booking or payment source is not found; or when the
|
|
1154
|
+
* charge fails.
|
|
1136
1155
|
*/
|
|
1137
1156
|
async makePayment(input) {
|
|
1157
|
+
this.validatePaymentInput(input);
|
|
1138
1158
|
const normalized = normalizeBookingId(input.bookingId);
|
|
1139
|
-
this.validatePaymentInput(input, normalized);
|
|
1140
1159
|
const onFile = await this.getPaymentsOnFile(normalized);
|
|
1141
1160
|
if (!onFile) {
|
|
1142
1161
|
throw new Error("Booking not found");
|
|
@@ -1177,8 +1196,8 @@ ${note}`;
|
|
|
1177
1196
|
* payments-on-file, then applies the refund.
|
|
1178
1197
|
*/
|
|
1179
1198
|
async refund(input) {
|
|
1199
|
+
this.validateRefundInput(input);
|
|
1180
1200
|
const normalized = normalizeBookingId(input.bookingId);
|
|
1181
|
-
this.validateRefundInput(input, normalized);
|
|
1182
1201
|
const onFile = await this.getPaymentsOnFile(normalized);
|
|
1183
1202
|
if (!onFile) {
|
|
1184
1203
|
throw new Error("Booking not found");
|
|
@@ -1217,9 +1236,7 @@ ${note}`;
|
|
|
1217
1236
|
}
|
|
1218
1237
|
/** Creates an invoice link for a booking's order. */
|
|
1219
1238
|
async createInvoiceLink(bookingId) {
|
|
1220
|
-
|
|
1221
|
-
throw new Error("bookingId is required");
|
|
1222
|
-
}
|
|
1239
|
+
assertBookingId(bookingId);
|
|
1223
1240
|
const normalized = normalizeBookingId(bookingId);
|
|
1224
1241
|
const booking = await this.getById(normalized);
|
|
1225
1242
|
if (!booking || !booking.orderId) {
|
|
@@ -1239,6 +1256,7 @@ ${note}`;
|
|
|
1239
1256
|
}
|
|
1240
1257
|
/** Returns the add-ons on a booking, grouped by add-on item (clean model). */
|
|
1241
1258
|
async listAddons(bookingId) {
|
|
1259
|
+
assertBookingId(bookingId);
|
|
1242
1260
|
const { items, displayId, orderId, normalizedBookingId } = await this.fetchBookingSale(bookingId);
|
|
1243
1261
|
const addons = items.map((item) => toBookingAddon(item)).filter((addon) => addon !== null);
|
|
1244
1262
|
return {
|
|
@@ -1273,6 +1291,7 @@ ${note}`;
|
|
|
1273
1291
|
* the underlying quote/order mutations fail.
|
|
1274
1292
|
*/
|
|
1275
1293
|
async addAddon(bookingId, input) {
|
|
1294
|
+
assertBookingId(bookingId);
|
|
1276
1295
|
const addonOptionId = (input?.addonOptionId || input?.addonId || "").trim();
|
|
1277
1296
|
if (!addonOptionId) {
|
|
1278
1297
|
throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);
|
|
@@ -1325,6 +1344,7 @@ ${note}`;
|
|
|
1325
1344
|
* variables. Returns the booking's add-ons after the change.
|
|
1326
1345
|
*/
|
|
1327
1346
|
async removeAddon(bookingId, input) {
|
|
1347
|
+
assertBookingId(bookingId);
|
|
1328
1348
|
const addonOptionId = (input?.addonOptionId || input?.addonId || "").trim();
|
|
1329
1349
|
if (!addonOptionId) {
|
|
1330
1350
|
throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);
|
|
@@ -1353,14 +1373,10 @@ ${note}`;
|
|
|
1353
1373
|
* booking matched, and parses the node into the internal model.
|
|
1354
1374
|
*/
|
|
1355
1375
|
async fetchBookingSale(bookingId) {
|
|
1356
|
-
const searchString = (bookingId || "").trim();
|
|
1357
|
-
if (!searchString) {
|
|
1358
|
-
throw new Error(ERROR_BOOKING_ID_REQUIRED);
|
|
1359
|
-
}
|
|
1360
1376
|
const body = await this.client.request(
|
|
1361
1377
|
SALES_ENDPOINT,
|
|
1362
1378
|
SALES_ADDONS_QUERY,
|
|
1363
|
-
buildSalesAddonsVariables(
|
|
1379
|
+
buildSalesAddonsVariables(bookingId)
|
|
1364
1380
|
);
|
|
1365
1381
|
const edges = body.data?.sales?.edges ?? [];
|
|
1366
1382
|
if (edges.length === 0) {
|
|
@@ -1543,7 +1559,7 @@ ${note}`;
|
|
|
1543
1559
|
}
|
|
1544
1560
|
return matched.productId;
|
|
1545
1561
|
}
|
|
1546
|
-
validatePaymentInput(input
|
|
1562
|
+
validatePaymentInput(input) {
|
|
1547
1563
|
if (!input.paymentSourceId || !input.paymentSourceId.startsWith(PAYMENT_SOURCE_PREFIX) && !ALLOWED_PAYMENT_SOURCE_IDS.includes(input.paymentSourceId)) {
|
|
1548
1564
|
throw new Error(
|
|
1549
1565
|
"paymentSourceId is required and must start with 'ps_' or be one of 'cash/cash', 'custom/other', 'custom/voucher'"
|
|
@@ -1552,16 +1568,16 @@ ${note}`;
|
|
|
1552
1568
|
assertAmount(input.amount);
|
|
1553
1569
|
assertCurrency(input.currency);
|
|
1554
1570
|
assertIdempotencyKey(input.idempotencyKey);
|
|
1555
|
-
assertBookingId(
|
|
1571
|
+
assertBookingId(input.bookingId);
|
|
1556
1572
|
}
|
|
1557
|
-
validateRefundInput(input
|
|
1573
|
+
validateRefundInput(input) {
|
|
1558
1574
|
if (!input.paymentId || !input.paymentId.startsWith(PAYMENT_ID_PREFIX)) {
|
|
1559
1575
|
throw new Error("paymentId is required and must start with 'pmt_'");
|
|
1560
1576
|
}
|
|
1561
1577
|
assertAmount(input.amount);
|
|
1562
1578
|
assertCurrency(input.currency);
|
|
1563
1579
|
assertIdempotencyKey(input.idempotencyKey);
|
|
1564
|
-
assertBookingId(
|
|
1580
|
+
assertBookingId(input.bookingId);
|
|
1565
1581
|
}
|
|
1566
1582
|
async fetchPaginated(query, baseParams, includeGuests, includePriceBreakdown) {
|
|
1567
1583
|
const bookings = [];
|
|
@@ -1601,9 +1617,14 @@ function assertIdempotencyKey(idempotencyKey) {
|
|
|
1601
1617
|
throw new Error("idempotencyKey is required");
|
|
1602
1618
|
}
|
|
1603
1619
|
}
|
|
1604
|
-
function assertBookingId(
|
|
1605
|
-
if (!
|
|
1606
|
-
throw new Error(
|
|
1620
|
+
function assertBookingId(bookingId) {
|
|
1621
|
+
if (!(BOOKING_DB_ID_REGEX.test(bookingId) || BOOKING_DISPLAY_ID_REGEX.test(bookingId))) {
|
|
1622
|
+
throw new Error(ERROR_INVALID_BOOKING_ID);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
function assertOrderId(orderId) {
|
|
1626
|
+
if (!(ORDER_DB_ID_REGEX.test(orderId) || ORDER_DISPLAY_ID_REGEX.test(orderId))) {
|
|
1627
|
+
throw new Error(ERROR_INVALID_ORDER_ID);
|
|
1607
1628
|
}
|
|
1608
1629
|
}
|
|
1609
1630
|
function validateCreateInput(input) {
|
|
@@ -1621,6 +1642,9 @@ function validateCreateInput(input) {
|
|
|
1621
1642
|
if (input.markAsPaid && !input.idempotencyKey) {
|
|
1622
1643
|
throw new Error("idempotencyKey is required when markAsPaid is set");
|
|
1623
1644
|
}
|
|
1645
|
+
if (input.parentOrderId) {
|
|
1646
|
+
assertOrderId(input.parentOrderId);
|
|
1647
|
+
}
|
|
1624
1648
|
}
|
|
1625
1649
|
function parseQuantity(value) {
|
|
1626
1650
|
if (typeof value !== "string" && typeof value !== "number") {
|