@curless/hotel-storefront 0.30.0 → 0.30.2
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/card.generated.d.ts +1 -1
- package/dist/card.generated.js +2 -2
- package/dist/card.generated.js.map +1 -1
- package/dist/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +68 -15
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/huazhu/client.d.ts.map +1 -1
- package/dist/huazhu/client.js +13 -2
- package/dist/huazhu/client.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.generated.js","sourceRoot":"","sources":["../src/card.generated.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,wEAAwE;AACxE,gFAAgF;AAChF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAW,MAAM,CAAC,IAAI,CAChD,
|
|
1
|
+
{"version":3,"file":"card.generated.js","sourceRoot":"","sources":["../src/card.generated.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,wEAAwE;AACxE,gFAAgF;AAChF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAW,MAAM,CAAC,IAAI,CAChD,87jiBAA87jiB,EAC97jiB,QAAQ,CACT,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAEnB,6GAA6G;AAC7G,MAAM,CAAC,MAAM,qBAAqB,GAChC,kEAAkE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/huazhu/backend.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,mBAAmB,EAExB,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/huazhu/backend.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,mBAAmB,EAExB,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAC;AAYvB,OAAO,EAAkB,KAAK,aAAa,EAAkC,MAAM,cAAc,CAAC;AAElG,OAAO,KAAK,EAAiB,eAAe,EAAkB,MAAM,yBAAyB,CAAC;AAE9F,OAAO,KAAK,EAcV,KAAK,EAKL,UAAU,EAGX,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,YAAY,EAGjB,KAAK,UAAU,EAEf,KAAK,aAAa,EAGnB,MAAM,eAAe,CAAC;AAWvB,OAAO,EAAE,KAAK,OAAO,EAA2C,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,KAAK,YAAY,EAAoC,MAAM,aAAa,CAAC;AAgBlF,OAAO,EAQL,KAAK,WAAW,EAChB,KAAK,WAAW,EAKjB,MAAM,WAAW,CAAC;AAsBnB,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,gGAAgG;IAChG,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACnD,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iIAAiI;IACjI,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,mBAgBjC,CAAC;AAEF,0GAA0G;AAC1G,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,OAGjD,CAAC;AAaF,eAAO,MAAM,aAAa,GAAI,OAAO,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,KAAG,MAKhE,CAAC;AAKF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,KAAK,CAAC;AAqJ5B;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,EAAE,OAAO,MAAM,KAAG,OAiB1D,CAAC;AA2BF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,WAAW,EAAE,EAAE,KAAK,MAAM,KAAG,WAAW,GAAG,SAGhF,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,WAAW,GAAI,QAAQ,WAAW,EAAE,EAAE,KAAK,MAAM,KAAG,WAAW,EAK3E,CAAC;AAUF,oFAAoF;AACpF,eAAO,MAAM,WAAW,GAAI,QAAQ,WAAW,EAAE,EAAE,KAAK,MAAM,KAAG,WAAW,EAO3E,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,IAAI,MAAM,EAAE,WAAU,IAAI,GAAG,IAAW,KAAG,MAKtF,CAAC;AAiCF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,UAAU,GAAG,SAAS,EAAE,GAAG,KAAK,KAAG,MAAM,GAAG,SAwB7E,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,MAAM,mBAAmB,KACxB,YAAY,GAAG;IAChB,YAAY,EAAE,mBAAmB,CAAC;IAClC,YAAY,IAAI,MAAM,EAAE,CAAC;IACzB,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;IACnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAk7E9B,CAAC"}
|
package/dist/huazhu/backend.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes, randomUUID } from 'node:crypto';
|
|
2
2
|
import { DEFAULT_PAGE, MAX_PAGE, REQUEST_KINDS, REQUEST_NOTE_MAX, guestTooLong, partyNeeds, } from '../backend.js';
|
|
3
|
-
import { addDays, atHotelTime, nights as nightsBetween, stayProblem, todayAt } from '../dates.js';
|
|
3
|
+
import { addDays, arrivalInstant, atHotelTime, nights as nightsBetween, stayProblem, todayAt, } from '../dates.js';
|
|
4
4
|
import { byWords, splitByStay } from '../demo-hotels.js';
|
|
5
5
|
import { FACILITIES, hasFacility } from '../facilities.js';
|
|
6
6
|
import { endOf, startProblem } from '../hourly.js';
|
|
@@ -699,6 +699,39 @@ export const createHuazhuHotels = (opts) => {
|
|
|
699
699
|
].filter((x) => !(x.roomType && x.roomType.status === 0));
|
|
700
700
|
};
|
|
701
701
|
const policyOf = (code) => parseCancelPolicy(code);
|
|
702
|
+
/**
|
|
703
|
+
* A free-cancellation deadline, no later than a room by the hour's start.
|
|
704
|
+
*
|
|
705
|
+
* ⚠️ CANCELLING IS BEFORE THE STAY. AD0_0 reads "free until the end of the
|
|
706
|
+
* arrival day", and a 15:00-19:00 room was offered as free to cancel until
|
|
707
|
+
* 24:00 - five hours after the guest left (eval, 2026-10-14). Once it has
|
|
708
|
+
* begun it is a no-show, as a night is after its night audit.
|
|
709
|
+
*/
|
|
710
|
+
const beforeStart = (until, date, start) => {
|
|
711
|
+
if (until === undefined || !start)
|
|
712
|
+
return until;
|
|
713
|
+
const at = arrivalInstant(date, start, opts.tz);
|
|
714
|
+
const capped = Math.min(until, at);
|
|
715
|
+
return capped > now() ? capped : undefined;
|
|
716
|
+
};
|
|
717
|
+
/** A line's free-cancellation fields: the room's, held to the start chosen. */
|
|
718
|
+
const freeOf = (room, date, start) => {
|
|
719
|
+
const until = room.freeCancellationUntil ? Date.parse(room.freeCancellationUntil) : undefined;
|
|
720
|
+
const held = beforeStart(until, date, start);
|
|
721
|
+
if (held === undefined)
|
|
722
|
+
return { freeCancellationUntil: undefined };
|
|
723
|
+
if (held === until)
|
|
724
|
+
return {
|
|
725
|
+
freeCancellationUntil: room.freeCancellationUntil,
|
|
726
|
+
...(room.freeCancellationLocal
|
|
727
|
+
? { freeCancellationLocal: room.freeCancellationLocal }
|
|
728
|
+
: {}),
|
|
729
|
+
};
|
|
730
|
+
return {
|
|
731
|
+
freeCancellationUntil: new Date(held).toISOString(),
|
|
732
|
+
freeCancellationLocal: deadlineAt(held, opts.tz, opts.language === 'en' ? 'en' : 'zh'),
|
|
733
|
+
};
|
|
734
|
+
};
|
|
702
735
|
const toRoom = (h, p, stay) => {
|
|
703
736
|
const s = p.res;
|
|
704
737
|
const cur = s.currency;
|
|
@@ -707,7 +740,9 @@ export const createHuazhuHotels = (opts) => {
|
|
|
707
740
|
const total = after.reduce((a, b) => a + b, 0);
|
|
708
741
|
const pre = s.before ? s.before.map((x) => toMinor(x, cur)).reduce((a, b) => a + b, 0) : total;
|
|
709
742
|
const policy = policyOf(s.cancelCode);
|
|
710
|
-
|
|
743
|
+
// A room by the hour: free at most until the latest it can start - the
|
|
744
|
+
// line with its start chosen says the start itself (`quoteLines`).
|
|
745
|
+
const freeUntil = beforeStart(policy ? freeUntilOf(policy, stay.checkIn, opts.tz, now()) : undefined, stay.checkIn, p.hourly?.latestStart);
|
|
711
746
|
const rt = p.roomType;
|
|
712
747
|
const beds = (rt?.bedTypeList ?? [])
|
|
713
748
|
.map((b) => [(en ? bedNameEn(b.bedTypeName) : undefined) ?? b.bedTypeName, b.bedSpec]
|
|
@@ -939,10 +974,7 @@ export const createHuazhuHotels = (opts) => {
|
|
|
939
974
|
unit: room.nightly,
|
|
940
975
|
total: money(preTax, room.stayTotal.currency),
|
|
941
976
|
refundable: room.refundable,
|
|
942
|
-
|
|
943
|
-
...(room.freeCancellationLocal
|
|
944
|
-
? { freeCancellationLocal: room.freeCancellationLocal }
|
|
945
|
-
: {}),
|
|
977
|
+
...freeOf(room, line.stay.checkIn, hourly?.start),
|
|
946
978
|
day: line.stay.checkIn,
|
|
947
979
|
});
|
|
948
980
|
}
|
|
@@ -1110,13 +1142,28 @@ export const createHuazhuHotels = (opts) => {
|
|
|
1110
1142
|
freeUntil: undefined,
|
|
1111
1143
|
};
|
|
1112
1144
|
}
|
|
1145
|
+
// A room by the hour that has begun is a no-show, whatever the code says
|
|
1146
|
+
// about the rest of the day - see `beforeStart`.
|
|
1147
|
+
if (b.hourly && now() >= arrivalInstant(b.stay.checkIn, b.hourly.start, b.tz)) {
|
|
1148
|
+
return {
|
|
1149
|
+
fee: total,
|
|
1150
|
+
forbidden: false,
|
|
1151
|
+
rule: `This room by the hour began at ${b.hourly.start}, so cancelling now is a no-show; the fee shown is the most it could be, and Huazhu works out the actual fee when it cancels.`,
|
|
1152
|
+
freeUntil: undefined,
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1113
1155
|
const penalty = penaltyAt(policy, b.stay.checkIn, b.tz, now());
|
|
1114
1156
|
const fee = feeFor(penalty, amounts);
|
|
1157
|
+
const freeUntil = b.hourly
|
|
1158
|
+
? beforeStart(freeUntilOf(policy, b.stay.checkIn, b.tz, now()), b.stay.checkIn, b.hourly.start)
|
|
1159
|
+
: freeUntilOf(policy, b.stay.checkIn, b.tz, now());
|
|
1115
1160
|
return {
|
|
1116
1161
|
fee: fee ?? total,
|
|
1117
1162
|
forbidden: fee === null,
|
|
1118
|
-
rule:
|
|
1119
|
-
|
|
1163
|
+
rule: b.hourly && freeUntil !== undefined && fee === 0
|
|
1164
|
+
? `Free to cancel until ${b.hourly.start} on ${b.stay.checkIn}, when the room by the hour begins; after that it is a no-show.`
|
|
1165
|
+
: describePolicy(policy, b.stay.checkIn, b.tz, amounts),
|
|
1166
|
+
freeUntil,
|
|
1120
1167
|
};
|
|
1121
1168
|
};
|
|
1122
1169
|
/**
|
|
@@ -2019,16 +2066,22 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2019
2066
|
if (priceEverything)
|
|
2020
2067
|
await pool(matches.map((m) => m.raw), PRICE_CONCURRENCY, priceHotel);
|
|
2021
2068
|
const canRoomFilter = priceEverything;
|
|
2022
|
-
// ⚠️ A HOTEL
|
|
2023
|
-
//
|
|
2024
|
-
//
|
|
2025
|
-
//
|
|
2026
|
-
|
|
2069
|
+
// ⚠️ A HOTEL THAT SELLS ROOMS BY THE HOUR TODAY STAYS, even when none
|
|
2070
|
+
// can be had now - with why, so the guest hears it:
|
|
2071
|
+
// - too small for the party: partyNeeds, so the card can offer more
|
|
2072
|
+
// rooms with fewer in each (香格里拉, 2026-10-12) - three guests were
|
|
2073
|
+
// shown no hotel at all, as if none sold rooms by the hour;
|
|
2074
|
+
// - the day's last start gone by, or not on sale yet: at 22:00 the
|
|
2075
|
+
// hotel the guest named was dropped and the model offered to look for
|
|
2076
|
+
// "others with rooms by the hour today" - there were none (eval,
|
|
2077
|
+
// 2026-10-13).
|
|
2078
|
+
const sellsTodayOnly = (raw) => {
|
|
2027
2079
|
const priced = pricedRooms.get(raw.hotelId) ?? [];
|
|
2028
|
-
return priced.length > 0 &&
|
|
2080
|
+
return (priced.length > 0 &&
|
|
2081
|
+
priced.every((p) => !p.res.ok && (p.res.kind === 'party' || p.res.kind === 'closed')));
|
|
2029
2082
|
};
|
|
2030
2083
|
if (canRoomFilter && (roomTerms || hourlyOnly))
|
|
2031
|
-
matches = matches.filter(({ raw }) => bestFor(raw, f) !== null || (hourlyOnly && !roomTerms &&
|
|
2084
|
+
matches = matches.filter(({ raw }) => bestFor(raw, f) !== null || (hourlyOnly && !roomTerms && sellsTodayOnly(raw)));
|
|
2032
2085
|
const currencies = [...new Set(matches.map((m) => m.hotel.currency))].sort();
|
|
2033
2086
|
const onePrice = currencies.length === 1;
|
|
2034
2087
|
const ceiling = priceEverything && onePrice && Number(q.maxNightly) > 0 ? Number(q.maxNightly) : undefined;
|