@curless/hotel-storefront 0.30.3 → 0.30.4
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/backend.d.ts +7 -1
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +9 -3
- package/dist/backend.js.map +1 -1
- 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/dates.d.ts +11 -0
- package/dist/dates.d.ts.map +1 -1
- package/dist/dates.js +30 -9
- package/dist/dates.js.map +1 -1
- package/dist/demo-hotels.d.ts.map +1 -1
- package/dist/demo-hotels.js +42 -10
- package/dist/demo-hotels.js.map +1 -1
- package/dist/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +97 -30
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/huazhu/sellable.d.ts +3 -1
- package/dist/huazhu/sellable.d.ts.map +1 -1
- package/dist/huazhu/sellable.js +22 -3
- package/dist/huazhu/sellable.js.map +1 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +13 -0
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
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, arrivalInstant, atHotelTime, nights as nightsBetween, stayProblem, todayAt, } from '../dates.js';
|
|
3
|
+
import { addDays, arrivalInstant, atHotelTime, nights as nightsBetween, stayProblem, stayProblemOf, 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';
|
|
@@ -583,6 +583,7 @@ export const createHuazhuHotels = (opts) => {
|
|
|
583
583
|
ok: false,
|
|
584
584
|
kind: 'too-far',
|
|
585
585
|
why: `rooms here are on sale at most ${sellDays} days ahead`,
|
|
586
|
+
args: { days: sellDays },
|
|
586
587
|
},
|
|
587
588
|
}))
|
|
588
589
|
.filter((x) => !(x.roomType && x.roomType.status === 0));
|
|
@@ -799,6 +800,18 @@ export const createHuazhuHotels = (opts) => {
|
|
|
799
800
|
...(maxChildren > 0 && maxChildren < 99 ? { maxChildren } : {}),
|
|
800
801
|
};
|
|
801
802
|
};
|
|
803
|
+
/** A party too big for any room here, said by partyNeeds with its numbers beside it. */
|
|
804
|
+
const partyWhy = (guests, largest) => ({
|
|
805
|
+
why: partyNeeds(guests, largest),
|
|
806
|
+
code: 'party',
|
|
807
|
+
...(largest > 0 ? { args: { largest, rooms: Math.ceil(guests / largest) } } : {}),
|
|
808
|
+
});
|
|
809
|
+
/** A hotel's "nothing to book", as HotelDetail carries it. */
|
|
810
|
+
const noRoomsOf = (w) => ({
|
|
811
|
+
noRooms: w.why,
|
|
812
|
+
noRoomsCode: w.code,
|
|
813
|
+
...(w.args ? { noRoomsArgs: w.args } : {}),
|
|
814
|
+
});
|
|
802
815
|
/** The most a room here sleeps, from rates refused for the party ("sleeps 2"). */
|
|
803
816
|
const largestOf = (fails) => Math.max(...fails.map((f) => Number(/\d+/.exec(f.why)?.[0] ?? 0)));
|
|
804
817
|
/**
|
|
@@ -811,49 +824,84 @@ export const createHuazhuHotels = (opts) => {
|
|
|
811
824
|
*/
|
|
812
825
|
const hourlyNoRoomsWhy = (priced, guests) => {
|
|
813
826
|
if (priced.length === 0)
|
|
814
|
-
return 'This hotel sells no rooms by the hour today.';
|
|
827
|
+
return { why: 'This hotel sells no rooms by the hour today.', code: 'hourly-none' };
|
|
815
828
|
const fails = priced.map((p) => p.res).filter((r) => !r.ok);
|
|
816
829
|
if (fails.length > 0 && fails.every((f) => f.kind === 'party'))
|
|
817
|
-
return
|
|
830
|
+
return partyWhy(guests, largestOf(fails));
|
|
818
831
|
if (fails.some((f) => f.kind === 'prepaid'))
|
|
819
|
-
return
|
|
832
|
+
return {
|
|
833
|
+
why: "This hotel's rooms by the hour are paid in advance, and this connector books rates paid at the hotel.",
|
|
834
|
+
code: 'prepaid-only',
|
|
835
|
+
};
|
|
820
836
|
const said = (re) => fails
|
|
821
837
|
.map((f) => (f.kind === 'closed' ? re.exec(f.why)?.[1] : undefined))
|
|
822
838
|
.filter((t) => !!t)
|
|
823
839
|
.sort();
|
|
824
840
|
const opens = said(/on sale today from (\d\d:\d\d)/)[0];
|
|
825
841
|
if (opens)
|
|
826
|
-
return
|
|
842
|
+
return {
|
|
843
|
+
why: `Rooms by the hour here go on sale today from ${opens}.`,
|
|
844
|
+
code: 'hourly-not-yet',
|
|
845
|
+
args: { opensAt: opens },
|
|
846
|
+
};
|
|
827
847
|
const last = said(/the last start today was (\d\d:\d\d)/).pop();
|
|
828
848
|
if (last)
|
|
829
|
-
return
|
|
830
|
-
|
|
849
|
+
return {
|
|
850
|
+
why: `No room by the hour is left here today: the last start today was ${last}.`,
|
|
851
|
+
code: 'hourly-over',
|
|
852
|
+
args: { lastStart: last },
|
|
853
|
+
};
|
|
854
|
+
return { why: 'No room by the hour is left here today.', code: 'sold-out' };
|
|
831
855
|
};
|
|
832
856
|
/** Why nothing here can be sold for these nights - the most useful reason first. */
|
|
833
857
|
const noRoomsWhy = (priced, stay, rooms) => {
|
|
834
858
|
if (priced.length === 0)
|
|
835
|
-
return
|
|
859
|
+
return {
|
|
860
|
+
why: 'This hotel has no rooms on sale through this connector.',
|
|
861
|
+
code: 'none-on-sale',
|
|
862
|
+
};
|
|
836
863
|
const fails = priced.map((p) => p.res).filter((r) => !r.ok);
|
|
837
864
|
const kinds = new Set(fails.map((f) => f.kind));
|
|
838
865
|
const only = (k) => kinds.size === 1 && kinds.has(k);
|
|
839
866
|
if (only('party'))
|
|
840
|
-
return
|
|
867
|
+
return partyWhy(stay.guests, largestOf(fails));
|
|
841
868
|
if (only('prepaid'))
|
|
842
|
-
return
|
|
869
|
+
return {
|
|
870
|
+
why: 'Every rate here for those nights is paid in advance, and this connector books rates paid at the hotel.',
|
|
871
|
+
code: 'prepaid-only',
|
|
872
|
+
};
|
|
843
873
|
if (only('sold-out'))
|
|
844
874
|
return rooms > 1
|
|
845
|
-
?
|
|
846
|
-
|
|
875
|
+
? {
|
|
876
|
+
why: `No room type here has ${rooms} left for those nights.`,
|
|
877
|
+
code: 'sold-out',
|
|
878
|
+
args: { rooms },
|
|
879
|
+
}
|
|
880
|
+
: { why: 'Every room type here is taken for those nights.', code: 'sold-out' };
|
|
847
881
|
if (only('too-many-rooms'))
|
|
848
|
-
return
|
|
882
|
+
return {
|
|
883
|
+
why: `No rate here books ${rooms} rooms at once; ask for fewer.`,
|
|
884
|
+
code: 'too-many-rooms',
|
|
885
|
+
args: { rooms },
|
|
886
|
+
};
|
|
849
887
|
if (only('too-far'))
|
|
850
|
-
return
|
|
888
|
+
return {
|
|
889
|
+
why: `Not on sale yet: ${fails[0]?.why ?? 'rooms here are not sold that far ahead'}.`,
|
|
890
|
+
code: 'too-far',
|
|
891
|
+
...(fails[0]?.args?.days ? { args: { days: fails[0].args.days } } : {}),
|
|
892
|
+
};
|
|
851
893
|
const rule = fails.find((f) => f.kind === 'stay-rule');
|
|
852
894
|
if (rule)
|
|
853
|
-
return
|
|
895
|
+
return {
|
|
896
|
+
why: `Not for those nights: ${rule.why}.`,
|
|
897
|
+
// Booked too far ahead for this rate is "too far", said with its days.
|
|
898
|
+
...(rule.args?.days !== undefined && !rule.args.rule
|
|
899
|
+
? { code: 'too-far', args: { days: rule.args.days } }
|
|
900
|
+
: { code: 'stay-rule', ...(rule.args ? { args: rule.args } : {}) }),
|
|
901
|
+
};
|
|
854
902
|
if (kinds.has('closed'))
|
|
855
|
-
return 'Not on sale for those nights.';
|
|
856
|
-
return 'No room here can be booked for those nights.';
|
|
903
|
+
return { why: 'Not on sale for those nights.', code: 'closed' };
|
|
904
|
+
return { why: 'No room here can be booked for those nights.', code: 'unavailable' };
|
|
857
905
|
};
|
|
858
906
|
// --------------------------------------------------------------- quote ----
|
|
859
907
|
const quoteLines = async (trip, fresh = false) => {
|
|
@@ -2037,11 +2085,14 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2037
2085
|
}
|
|
2038
2086
|
catch {
|
|
2039
2087
|
pricedRooms.set(raw.hotelId, []);
|
|
2040
|
-
why.set(raw.hotelId,
|
|
2088
|
+
why.set(raw.hotelId, {
|
|
2089
|
+
why: 'Rooms by the hour could not be read from Huazhu just now; open the hotel for them.',
|
|
2090
|
+
code: 'unreachable',
|
|
2091
|
+
});
|
|
2041
2092
|
}
|
|
2042
2093
|
return;
|
|
2043
2094
|
}
|
|
2044
|
-
const problem =
|
|
2095
|
+
const problem = stayProblemOf(stay, today());
|
|
2045
2096
|
if (problem) {
|
|
2046
2097
|
pricedRooms.set(raw.hotelId, []);
|
|
2047
2098
|
why.set(raw.hotelId, problem);
|
|
@@ -2055,9 +2106,12 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2055
2106
|
}
|
|
2056
2107
|
catch (err) {
|
|
2057
2108
|
pricedRooms.set(raw.hotelId, []);
|
|
2058
|
-
why.set(raw.hotelId,
|
|
2059
|
-
|
|
2060
|
-
|
|
2109
|
+
why.set(raw.hotelId, {
|
|
2110
|
+
why: err instanceof HuazhuRefusal && err.code === 2009
|
|
2111
|
+
? 'Huazhu is answering slowly just now; open the hotel for its rooms.'
|
|
2112
|
+
: 'Prices could not be read from Huazhu just now; open the hotel for its rooms.',
|
|
2113
|
+
code: 'unreachable',
|
|
2114
|
+
});
|
|
2061
2115
|
}
|
|
2062
2116
|
};
|
|
2063
2117
|
const bestFor = (raw, over) => {
|
|
@@ -2157,11 +2211,18 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2157
2211
|
if (!stay)
|
|
2158
2212
|
return m.hotel;
|
|
2159
2213
|
const b = bestFor(m.raw, f);
|
|
2160
|
-
if (!b)
|
|
2214
|
+
if (!b) {
|
|
2215
|
+
const w = why.get(m.raw.hotelId) ?? {
|
|
2216
|
+
why: 'No room here can be booked for those nights.',
|
|
2217
|
+
code: 'unavailable',
|
|
2218
|
+
};
|
|
2161
2219
|
return {
|
|
2162
2220
|
...m.hotel,
|
|
2163
|
-
noRoomsForStay: why
|
|
2221
|
+
noRoomsForStay: w.why,
|
|
2222
|
+
noRoomsForStayCode: w.code,
|
|
2223
|
+
...(w.args ? { noRoomsForStayArgs: w.args } : {}),
|
|
2164
2224
|
};
|
|
2225
|
+
}
|
|
2165
2226
|
return {
|
|
2166
2227
|
...m.hotel,
|
|
2167
2228
|
forStay: {
|
|
@@ -2250,9 +2311,9 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2250
2311
|
const detail = { hotel: toHotel(raw, view, now()) };
|
|
2251
2312
|
if (!stay)
|
|
2252
2313
|
return detail;
|
|
2253
|
-
const problem =
|
|
2314
|
+
const problem = stayProblemOf(stay, today());
|
|
2254
2315
|
if (problem)
|
|
2255
|
-
return { ...detail,
|
|
2316
|
+
return { ...detail, ...noRoomsOf(problem) };
|
|
2256
2317
|
let priced;
|
|
2257
2318
|
try {
|
|
2258
2319
|
priced = await priceStay(raw, stay, 1);
|
|
@@ -2261,7 +2322,10 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2261
2322
|
return {
|
|
2262
2323
|
...detail,
|
|
2263
2324
|
stay,
|
|
2264
|
-
|
|
2325
|
+
...noRoomsOf({
|
|
2326
|
+
why: `Huazhu could not be asked for this hotel's rooms just now (${err instanceof HuazhuRefusal ? err.huazhuMessage : 'no answer'}). Try again in a moment.`,
|
|
2327
|
+
code: 'unreachable',
|
|
2328
|
+
}),
|
|
2265
2329
|
};
|
|
2266
2330
|
}
|
|
2267
2331
|
const rooms = priced
|
|
@@ -2272,7 +2336,7 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2272
2336
|
...detail,
|
|
2273
2337
|
stay,
|
|
2274
2338
|
rooms,
|
|
2275
|
-
...(rooms.length === 0 ?
|
|
2339
|
+
...(rooms.length === 0 ? noRoomsOf(noRoomsWhy(priced, stay, 1)) : {}),
|
|
2276
2340
|
};
|
|
2277
2341
|
},
|
|
2278
2342
|
async hourlyRooms(id, guests) {
|
|
@@ -2290,7 +2354,10 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2290
2354
|
return {
|
|
2291
2355
|
hotel,
|
|
2292
2356
|
stay,
|
|
2293
|
-
|
|
2357
|
+
...noRoomsOf({
|
|
2358
|
+
why: `Huazhu could not be asked for this hotel's rooms by the hour just now (${err instanceof HuazhuRefusal ? err.huazhuMessage : 'no answer'}). Try again in a moment.`,
|
|
2359
|
+
code: 'unreachable',
|
|
2360
|
+
}),
|
|
2294
2361
|
};
|
|
2295
2362
|
}
|
|
2296
2363
|
const rooms = priced
|
|
@@ -2301,7 +2368,7 @@ export const createHuazhuHotels = (opts) => {
|
|
|
2301
2368
|
hotel,
|
|
2302
2369
|
stay,
|
|
2303
2370
|
rooms,
|
|
2304
|
-
...(rooms.length === 0 ?
|
|
2371
|
+
...(rooms.length === 0 ? noRoomsOf(hourlyNoRoomsWhy(priced, guests)) : {}),
|
|
2305
2372
|
};
|
|
2306
2373
|
},
|
|
2307
2374
|
async datesAround(id, stay, o) {
|