@curless/hotel-storefront 0.49.0 → 0.49.1
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/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +21 -51
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/huazhu/bookings.d.ts.map +1 -1
- package/dist/huazhu/bookings.js +1 -1
- package/dist/huazhu/bookings.js.map +1 -1
- package/dist/huazhu/catalog.d.ts +0 -1
- package/dist/huazhu/catalog.d.ts.map +1 -1
- package/dist/huazhu/catalog.js +7 -28
- package/dist/huazhu/catalog.js.map +1 -1
- package/dist/present.d.ts +5 -0
- package/dist/present.d.ts.map +1 -1
- package/dist/present.js +8 -0
- package/dist/present.js.map +1 -1
- package/dist/same-booking.d.ts.map +1 -1
- package/dist/same-booking.js +6 -5
- package/dist/same-booking.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -2
- package/dist/server.js.map +1 -1
- package/dist/sessions.d.ts +26 -1
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +35 -2
- package/dist/sessions.js.map +1 -1
- package/dist/tools.d.ts +18 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +70 -3
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
|
@@ -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,EASlB,MAAM,eAAe,CAAC;AAavB,OAAO,EAEL,KAAK,aAAa,EAKnB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,QAAQ,EAAiC,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAGL,KAAK,eAAe,EAIrB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/huazhu/backend.ts"],"names":[],"mappings":"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"}
|
package/dist/huazhu/backend.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomBytes, randomUUID } from 'node:crypto';
|
|
2
2
|
import { DEFAULT_PAGE, MAX_PAGE, REQUEST_KINDS, REQUEST_NOTE_MAX, guestTooLong, partyNeedsOf, } from '../backend.js';
|
|
3
3
|
import { addDays, arrivalInstant, atHotelTime, nights as nightsBetween, stayProblem, stayProblemOf, todayAt, } from '../dates.js';
|
|
4
4
|
import { byWords, splitByStay } from '../demo-hotels.js';
|
|
@@ -8,6 +8,7 @@ import { BOOKING_LIMITS, DAY_MS, HOUR_MS, UNPAID_PER_STRICT, WindowCounter, } fr
|
|
|
8
8
|
import { formatMoney, minorFactor, money, multiplyMoney, toMinor } from '../money.js';
|
|
9
9
|
import { UnionPayError, expiryMMyy, lastFour, } from '../payments/unionpay.js';
|
|
10
10
|
import { bedKindsOf } from '../room-filters.js';
|
|
11
|
+
import { SAME_BOOKING_MS, guestDigest, singleFlight } from '../same-booking.js';
|
|
11
12
|
import { MAX_ROOMS_PER_LINE, quoteLineKey } from '../trip.js';
|
|
12
13
|
import { IN_REQUEST_AT_MS, NOT_FOUND, StoreWriteError, nextCheckAt, statusOf, } from './bookings.js';
|
|
13
14
|
import { describePolicy, feeFor, freeUntilOf, nightAuditOf, parseCancelPolicy, penaltyAt, phasesOf, refundableFrom, stepsOf, } from './cancel-policy.js';
|
|
@@ -62,8 +63,6 @@ export const newPublicCode = (taken) => {
|
|
|
62
63
|
return code;
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
|
-
/** The same booking asked for again this soon - same conversation, email, stays and guest (`tripKey`) - is answered with the first. */
|
|
66
|
-
const SAME_TRIP_MS = 10 * 60_000;
|
|
67
66
|
/**
|
|
68
67
|
* The most hotels priced for one search. A city can hold hundreds of Huazhu
|
|
69
68
|
* hotels, and every one priced is two calls to Huazhu; past this, the page is
|
|
@@ -563,43 +562,23 @@ export const createHuazhuHotels = (opts) => {
|
|
|
563
562
|
const unpaidAsk = (b) => !!b.prepaid &&
|
|
564
563
|
!paidInAdvance(b.prepaid) &&
|
|
565
564
|
(b.status === 'awaiting-payment' || b.status === 'expired');
|
|
566
|
-
/**
|
|
567
|
-
const
|
|
565
|
+
/** Every booking request asked and not yet answered - what `drain` waits for. */
|
|
566
|
+
const asking = new Set();
|
|
568
567
|
/** Set by `drain`: a stopping process starts no booking. */
|
|
569
568
|
let closing = false;
|
|
570
569
|
/**
|
|
571
|
-
* One booking request at a time per conversation and per email
|
|
572
|
-
*
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
* audit, P1-2). The second waits for the first, then finds its trip
|
|
577
|
-
* already booked.
|
|
570
|
+
* One booking request at a time per conversation and per email - the shared
|
|
571
|
+
* `singleFlight` (`../same-booking.js`), whose reasons it keeps (2026-10-05
|
|
572
|
+
* audit, P1-2: two at once booked twice). Every request asked through it is
|
|
573
|
+
* also remembered in `asking` until it is answered, for `drain`: the shared
|
|
574
|
+
* helper keeps its locks to itself.
|
|
578
575
|
*/
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
if (busy.length === 0)
|
|
586
|
-
break;
|
|
587
|
-
await Promise.allSettled(busy);
|
|
588
|
-
}
|
|
589
|
-
// Nothing awaited between the check above and these lines: no other
|
|
590
|
-
// request can slip in.
|
|
591
|
-
const p = run();
|
|
592
|
-
const done = p.then(() => undefined, () => undefined);
|
|
593
|
-
for (const k of keys)
|
|
594
|
-
flights.set(k, done);
|
|
595
|
-
try {
|
|
596
|
-
return await p;
|
|
597
|
-
}
|
|
598
|
-
finally {
|
|
599
|
-
for (const k of keys)
|
|
600
|
-
if (flights.get(k) === done)
|
|
601
|
-
flights.delete(k);
|
|
602
|
-
}
|
|
576
|
+
const sameBooking = singleFlight();
|
|
577
|
+
const single = (keys, run) => {
|
|
578
|
+
const asked = sameBooking(keys, run);
|
|
579
|
+
asking.add(asked);
|
|
580
|
+
void asked.finally(() => asking.delete(asked)).catch(() => { });
|
|
581
|
+
return asked;
|
|
603
582
|
};
|
|
604
583
|
// ------------------------------------------------------------- lookups ----
|
|
605
584
|
/**
|
|
@@ -1728,8 +1707,6 @@ export const createHuazhuHotels = (opts) => {
|
|
|
1728
1707
|
* matched by.
|
|
1729
1708
|
*/
|
|
1730
1709
|
const conversationOf = (who) => who.tripOwner ?? who.sessionId;
|
|
1731
|
-
/** A name for a booking in what the guest is told. */
|
|
1732
|
-
const named = (b) => `${b.hotelName} (${b.confirmationCode})`;
|
|
1733
1710
|
/**
|
|
1734
1711
|
* A booking that still counts against the limits on bookings still to come
|
|
1735
1712
|
* (`perEmailLive`, `perConversationLive`) - and the one set the guest is told
|
|
@@ -1778,7 +1755,7 @@ export const createHuazhuHotels = (opts) => {
|
|
|
1778
1755
|
.filter((b) => b.tripKey === tripKey &&
|
|
1779
1756
|
b.owners.includes(conversationOf(who)) &&
|
|
1780
1757
|
b.guest.email.trim().toLowerCase() === email &&
|
|
1781
|
-
now() - Date.parse(b.createdAt) <
|
|
1758
|
+
now() - Date.parse(b.createdAt) < SAME_BOOKING_MS &&
|
|
1782
1759
|
isLive(b));
|
|
1783
1760
|
const ref = earlier[0]?.tripRef;
|
|
1784
1761
|
const before = ref ? store.intent(ref) : undefined;
|
|
@@ -3549,7 +3526,7 @@ export const createHuazhuHotels = (opts) => {
|
|
|
3549
3526
|
closing = true;
|
|
3550
3527
|
// The steps on payments too - a refund or a booking half taken when the
|
|
3551
3528
|
// process stopped was lost (audit P1-3, P0-B).
|
|
3552
|
-
await Promise.allSettled([...
|
|
3529
|
+
await Promise.allSettled([...asking, ...steps]);
|
|
3553
3530
|
},
|
|
3554
3531
|
async searchHotels(q) {
|
|
3555
3532
|
const terms = (q.query ?? '')
|
|
@@ -4082,17 +4059,10 @@ export const createHuazhuHotels = (opts) => {
|
|
|
4082
4059
|
// says it again in other words - 「需要安静的房间」 then 「希望房间安静」 -
|
|
4083
4060
|
// which booked a second room, or opened a second payment. The requests
|
|
4084
4061
|
// are a closed list and the arrival a time; the name and the phone are
|
|
4085
|
-
// the same person written two ways (full-width, spacing) made one.
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
same(guest.name),
|
|
4090
|
-
(guest.phone ?? '').normalize('NFKC').replace(/\D/g, ''),
|
|
4091
|
-
[...(requests?.kinds ?? [])].sort(),
|
|
4092
|
-
requests?.arrivingAt ?? '',
|
|
4093
|
-
]))
|
|
4094
|
-
.digest('hex')
|
|
4095
|
-
.slice(0, 16);
|
|
4062
|
+
// the same person written two ways (full-width, spacing) made one. The
|
|
4063
|
+
// digest is the shared `guestDigest` (`../same-booking.js`, also the
|
|
4064
|
+
// demonstration backend's); the key around it stays this backend's.
|
|
4065
|
+
const whoFor = guestDigest(guest, requests);
|
|
4096
4066
|
const tripKey = `${lines
|
|
4097
4067
|
.map((l) => l.kind === 'room'
|
|
4098
4068
|
? `${l.hotelId}|${l.roomId}|${l.stay.checkIn}|${l.stay.checkOut}|${l.stay.guests}|${l.rooms ?? 1}|${l.hourly?.start ?? ''}`
|