@curless/hotel-storefront 0.24.4 → 0.26.0
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/__tests__/__helpers__/sessions.d.ts +10 -0
- package/dist/__tests__/__helpers__/sessions.d.ts.map +1 -0
- package/dist/__tests__/__helpers__/sessions.js +37 -0
- package/dist/__tests__/__helpers__/sessions.js.map +1 -0
- package/dist/__tests__/card-contract.test.js +20 -0
- package/dist/__tests__/card-contract.test.js.map +1 -1
- package/dist/__tests__/data.test.js +7 -1
- package/dist/__tests__/data.test.js.map +1 -1
- package/dist/__tests__/dates.test.js +13 -1
- package/dist/__tests__/dates.test.js.map +1 -1
- package/dist/__tests__/huazhu-audit.test.js +69 -4
- package/dist/__tests__/huazhu-audit.test.js.map +1 -1
- package/dist/__tests__/huazhu-backend.test.js +93 -0
- package/dist/__tests__/huazhu-backend.test.js.map +1 -1
- package/dist/__tests__/huazhu-sandbox.test.js +7 -1
- package/dist/__tests__/huazhu-sandbox.test.js.map +1 -1
- package/dist/__tests__/server.test.js +112 -3
- package/dist/__tests__/server.test.js.map +1 -1
- package/dist/__tests__/state.test.d.ts +2 -0
- package/dist/__tests__/state.test.d.ts.map +1 -0
- package/dist/__tests__/state.test.js +204 -0
- package/dist/__tests__/state.test.js.map +1 -0
- package/dist/__tests__/tools.test.js +18 -0
- package/dist/__tests__/tools.test.js.map +1 -1
- package/dist/backend.d.ts +5 -0
- package/dist/backend.d.ts.map +1 -1
- 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/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -11
- package/dist/config.js.map +1 -1
- package/dist/dates.d.ts +9 -0
- package/dist/dates.d.ts.map +1 -1
- package/dist/dates.js +32 -0
- package/dist/dates.js.map +1 -1
- package/dist/demo-hotels.d.ts +21 -1
- package/dist/demo-hotels.d.ts.map +1 -1
- package/dist/demo-hotels.js +83 -11
- package/dist/demo-hotels.js.map +1 -1
- package/dist/huazhu/backend.d.ts +5 -0
- package/dist/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +67 -9
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/legal.d.ts +8 -1
- package/dist/legal.d.ts.map +1 -1
- package/dist/legal.js +22 -8
- package/dist/legal.js.map +1 -1
- package/dist/limits.d.ts +49 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +45 -0
- package/dist/limits.js.map +1 -1
- package/dist/members.d.ts +3 -1
- package/dist/members.d.ts.map +1 -1
- package/dist/members.js +24 -6
- package/dist/members.js.map +1 -1
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +8 -1
- package/dist/money.js.map +1 -1
- package/dist/server.d.ts +22 -8
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +121 -37
- package/dist/server.js.map +1 -1
- package/dist/sessions.d.ts +19 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +96 -0
- package/dist/sessions.js.map +1 -0
- package/dist/state.d.ts +32 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +118 -0
- package/dist/state.js.map +1 -0
- package/dist/tools.d.ts +13 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +69 -5
- package/dist/tools.js.map +1 -1
- package/dist/trip-ids.d.ts +8 -1
- package/dist/trip-ids.d.ts.map +1 -1
- package/dist/trip-ids.js +24 -1
- package/dist/trip-ids.js.map +1 -1
- package/dist/trip.d.ts +3 -1
- package/dist/trip.d.ts.map +1 -1
- package/dist/trip.js +23 -6
- package/dist/trip.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- 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,8wlYAA8wlY,EAC9wlY,QAAQ,CACT,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAEnB,2FAA2F;AAC3F,MAAM,CAAC,MAAM,qBAAqB,GAChC,kEAAkE,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BookingLimits } from './limits.js';
|
|
1
2
|
/**
|
|
2
3
|
* One hotel group's identity, vocabulary and wiring.
|
|
3
4
|
*
|
|
@@ -163,6 +164,12 @@ export type ApiSource = {
|
|
|
163
164
|
* loss of showing one to the wrong guest on us.
|
|
164
165
|
*/
|
|
165
166
|
allowTags?: string[];
|
|
167
|
+
/**
|
|
168
|
+
* How much booking one email, conversation, network and the whole
|
|
169
|
+
* deployment may do - see `BookingLimits` in limits.ts. Each number left out
|
|
170
|
+
* keeps its default.
|
|
171
|
+
*/
|
|
172
|
+
limits?: Partial<BookingLimits>;
|
|
166
173
|
};
|
|
167
174
|
/**
|
|
168
175
|
* The tool names this config produces.
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,WAAW,GAAG;IACxB,sFAAsF;IACtF,EAAE,EAAE,MAAM,CAAC;IAEX,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IAEd,qDAAqD;IACrD,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB;;;;;;WAMG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,sFAAsF;QACtF,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,iCAAiC;IACjC,IAAI,EAAE;QACJ;;;;;;WAMG;QACH,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;QACvB,gFAAgF;QAChF,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,mDAAmD;QACnD,GAAG,CAAC,EAAE,SAAS,CAAC;QAChB;;;;;WAKG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF;;;;;OAKG;IACH,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;KACzB,CAAC;IAEF,2GAA2G;IAC3G,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,6EAA6E;QAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IAEF,KAAK,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,mEAAmE;QACnE,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,QAAQ,CAAC;IACnB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0GAA0G;IAC1G,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One hotel group's identity, vocabulary and wiring.
|
|
3
|
-
*
|
|
4
|
-
* Same bargain as the shopping connector's `StorefrontConfig`: a second brand
|
|
5
|
-
* is a JSON file, never a fork. What differs is the seam - a shop config points
|
|
6
|
-
* at a Shopify domain, this one points at a `HotelBackend`, because the group's
|
|
7
|
-
* own booking API is coming and the demo data has to step aside without the
|
|
8
|
-
* config shape changing.
|
|
9
|
-
*
|
|
10
|
-
* Secrets never live here. They arrive through the environment.
|
|
11
|
-
*/
|
|
12
1
|
const slug = (s) => s
|
|
13
2
|
.toLowerCase()
|
|
14
3
|
.replace(/[^a-z0-9]+/g, '_')
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAyLA,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CACjC,CAAC;KACE,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;KAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAmC,EAAE,EAAE;IAC/D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,OAAO,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;IAC7D,OAAO;QACL,UAAU,EAAE,QAAQ,MAAM,GAAG,MAAM,EAAE;QACrC,QAAQ,EAAE,OAAO,MAAM,GAAG,IAAI,EAAE;QAChC,yEAAyE;QACzE,0EAA0E;QAC1E,+CAA+C;QAC/C,MAAM,EAAE,WAAW,MAAM,GAAG,MAAM,EAAE;QACpC,UAAU,EAAE,QAAQ,MAAM,QAAQ;QAClC,SAAS,EAAE,UAAU,MAAM,MAAM;QACjC,QAAQ,EAAE,QAAQ,MAAM,MAAM;QAC9B,SAAS,EAAE,SAAS,MAAM,MAAM;QAChC,cAAc,EAAE,WAAW,MAAM,SAAS;QAC1C,YAAY,EAAE,WAAW,MAAM,UAAU;QACzC,mBAAmB,EAAE,WAAW,MAAM,cAAc;QACpD,aAAa,EAAE,UAAU,MAAM,SAAS;QACxC,yEAAyE;QACzE,kEAAkE;QAClE,aAAa,EAAE,WAAW,MAAM,gBAAgB;QAChD,aAAa,EAAE,UAAU,MAAM,SAAS;QACxC,QAAQ,EAAE,OAAO,MAAM,GAAG,IAAI,WAAW;QACzC,wEAAwE;QACxE,2EAA2E;QAC3E,6DAA6D;QAC7D,OAAO,EAAE,WAAW,MAAM,GAAG,MAAM,EAAE;QACrC,SAAS,EAAE,QAAQ,MAAM,WAAW;QACpC,MAAM,EAAE,WAAW,MAAM,QAAQ;QACjC,OAAO,EAAE,YAAY,MAAM,QAAQ;QACnC,iBAAiB,EAAE,UAAU,MAAM,aAAa;KACxC,CAAC;AACb,CAAC,CAAC"}
|
package/dist/dates.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ export declare const eachNight: (checkIn: string, checkOut: string) => string[];
|
|
|
10
10
|
export declare const isWeekendNight: (day: string) => boolean;
|
|
11
11
|
/** The hotel's own today, in its own zone (`Europe/Paris`) or offset (`+08:00`). */
|
|
12
12
|
export declare const todayAt: (now: number, tz: string) => string;
|
|
13
|
+
/**
|
|
14
|
+
* An instant as the hotel's own clock shows it - "Sat 17 Oct, 15:00".
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ A DEADLINE WITHOUT ITS HOUR IS NOT A DEADLINE. A free-cancellation window
|
|
17
|
+
* that closes at 15:00 was shown as "until 2026-10-17", and a guest cancelling
|
|
18
|
+
* that evening would have been charged a night (2026-10-05 audit). In the
|
|
19
|
+
* hotel's time, because that is the clock the desk will hold them to.
|
|
20
|
+
*/
|
|
21
|
+
export declare const atHotelTime: (instant: number, tz: string) => string;
|
|
13
22
|
/** The moment a guest can walk in, as an instant. */
|
|
14
23
|
export declare const arrivalInstant: (checkIn: string, checkInFrom: string, tz: string) => number;
|
|
15
24
|
export declare const MAX_NIGHTS = 30;
|
package/dist/dates.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,MAAM,WAAa,CAAC;AAEjC,eAAO,MAAM,KAAK,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,MAIpB,CAAC;AAErB,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,MAAiD,CAAC;AAErF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,EAAE,GAAG,MAAM,KAAG,MAAqC,CAAC;AAEvF,qEAAqE;AACrE,eAAO,MAAM,MAAM,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MACR,CAAC;AAEpD,kFAAkF;AAClF,eAAO,MAAM,SAAS,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MAAM,EAKnE,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,OAG5C,CAAC;AAcF,oFAAoF;AACpF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,EAAE,IAAI,MAAM,KAAG,MAqBjD,CAAC;AAwBF,qDAAqD;AACrD,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,aAAa,MAAM,EAAE,IAAI,MAAM,KAAG,MAMjF,CAAC;AAEF,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,uFAAuF;AACvF,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EACjE,OAAO,MAAM,KACZ,MAAM,GAAG,IAiBX,CAAC"}
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,MAAM,WAAa,CAAC;AAEjC,eAAO,MAAM,KAAK,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,MAIpB,CAAC;AAErB,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,MAAiD,CAAC;AAErF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,EAAE,GAAG,MAAM,KAAG,MAAqC,CAAC;AAEvF,qEAAqE;AACrE,eAAO,MAAM,MAAM,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MACR,CAAC;AAEpD,kFAAkF;AAClF,eAAO,MAAM,SAAS,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MAAM,EAKnE,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,OAG5C,CAAC;AAcF,oFAAoF;AACpF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,EAAE,IAAI,MAAM,KAAG,MAqBjD,CAAC;AAwBF;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,EAAE,IAAI,MAAM,KAAG,MAwBzD,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,aAAa,MAAM,EAAE,IAAI,MAAM,KAAG,MAMjF,CAAC;AAEF,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,uFAAuF;AACvF,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EACjE,OAAO,MAAM,KACZ,MAAM,GAAG,IAiBX,CAAC"}
|
package/dist/dates.js
CHANGED
|
@@ -86,6 +86,38 @@ const offsetOn = (day, tz) => {
|
|
|
86
86
|
return '+00:00';
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* An instant as the hotel's own clock shows it - "Sat 17 Oct, 15:00".
|
|
91
|
+
*
|
|
92
|
+
* ⚠️ A DEADLINE WITHOUT ITS HOUR IS NOT A DEADLINE. A free-cancellation window
|
|
93
|
+
* that closes at 15:00 was shown as "until 2026-10-17", and a guest cancelling
|
|
94
|
+
* that evening would have been charged a night (2026-10-05 audit). In the
|
|
95
|
+
* hotel's time, because that is the clock the desk will hold them to.
|
|
96
|
+
*/
|
|
97
|
+
export const atHotelTime = (instant, tz) => {
|
|
98
|
+
const style = {
|
|
99
|
+
weekday: 'short',
|
|
100
|
+
day: 'numeric',
|
|
101
|
+
month: 'short',
|
|
102
|
+
hour: '2-digit',
|
|
103
|
+
minute: '2-digit',
|
|
104
|
+
hourCycle: 'h23',
|
|
105
|
+
};
|
|
106
|
+
if (isZone(tz)) {
|
|
107
|
+
try {
|
|
108
|
+
return new Intl.DateTimeFormat('en-GB', { ...style, timeZone: tz }).format(instant);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// An unknown zone falls through to UTC, said as UTC.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const m = /^([+-])(\d{2}):(\d{2})$/.exec(tz);
|
|
115
|
+
const shift = m
|
|
116
|
+
? (m[1] === '-' ? -1 : 1) * (Number(m[2] ?? 0) * 60 + Number(m[3] ?? 0)) * 60_000
|
|
117
|
+
: 0;
|
|
118
|
+
const shown = new Intl.DateTimeFormat('en-GB', { ...style, timeZone: 'UTC' }).format(instant + shift);
|
|
119
|
+
return m || isZone(tz) ? shown : `${shown} UTC`;
|
|
120
|
+
};
|
|
89
121
|
/** The moment a guest can walk in, as an instant. */
|
|
90
122
|
export const arrivalInstant = (checkIn, checkInFrom, tz) => {
|
|
91
123
|
const time = checkInFrom.length === 5 ? checkInFrom : '15:00';
|
package/dist/dates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,mEAAmE;AAEnE,oFAAoF;AACpF,MAAM,EAAE,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC;AAEnE,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC;AAEjC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAU,EAAe,EAAE,CAC/C,OAAO,CAAC,KAAK,QAAQ;IACrB,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7B,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAErB,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAErF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;AAEvF,qEAAqE;AACrE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAe,EAAE,QAAgB,EAAU,EAAE,CAClE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AAEpD,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAe,EAAE,QAAgB,EAAY,EAAE;IACvE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/C,KAAK,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAW,EAAE;IACrD,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IAC1C,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,GAAG,CAAC,EAAU,EAAW,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAEzD,oFAAoF;AACpF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAU,EAAU,EAAE;IACzD,IAAI,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QACf,IAAI,CAAC;YACH,wEAAwE;YACxE,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;gBACtC,QAAQ,EAAE,EAAE;gBACZ,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,SAAS;gBAChB,GAAG,EAAE,SAAS;aACf,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,4DAA4D;YAC5D,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC;QACb,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM;QACjF,CAAC,CAAC,CAAC,CAAC;IACN,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAU,EAAU,EAAE;IACnD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;YAC7C,QAAQ,EAAE,EAAE;YACZ,YAAY,EAAE,YAAY;YAC1B,IAAI,EAAE,SAAS;SAChB,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACvE,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF,qDAAqD;AACrD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAE,EAAU,EAAU,EAAE;IACzF,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9D,8EAA8E;IAC9E,oEAAoE;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,IAAI,MAAM,MAAM,EAAE,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,uFAAuF;AACvF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAiE,EACjE,KAAa,EACE,EAAE;IACjB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,0CAA0C,CAAC;IAC5E,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,2CAA2C,CAAC;IAC9E,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI,CAAC;QACR,OAAO,gFAAgF,CAAC;IAC1F,IAAI,CAAC,GAAG,UAAU;QAChB,OAAO,+BAA+B,UAAU,mCAAmC,CAAC,GAAG,CAAC;IAC1F,IAAI,IAAI,CAAC,OAAO,GAAG,KAAK;QAAE,OAAO,YAAY,IAAI,CAAC,OAAO,8BAA8B,KAAK,GAAG,CAAC;IAChG,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,cAAc;QAC9C,OAAO,yBAAyB,cAAc,gBAAgB,IAAI,CAAC,OAAO,kBAAkB,CAAC;IAC/F,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QACvE,OAAO,yDAAyD,CAAC;IACnE,IAAI,MAAM,GAAG,UAAU;QACrB,OAAO,aAAa,UAAU,+CAA+C,CAAC;IAChF,OAAO,IAAI,CAAC;AACd,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,mEAAmE;AAEnE,oFAAoF;AACpF,MAAM,EAAE,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC;AAEnE,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC;AAEjC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAU,EAAe,EAAE,CAC/C,OAAO,CAAC,KAAK,QAAQ;IACrB,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7B,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAErB,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAErF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;AAEvF,qEAAqE;AACrE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAe,EAAE,QAAgB,EAAU,EAAE,CAClE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AAEpD,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAe,EAAE,QAAgB,EAAY,EAAE;IACvE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/C,KAAK,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAW,EAAE;IACrD,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IAC1C,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,GAAG,CAAC,EAAU,EAAW,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAEzD,oFAAoF;AACpF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAU,EAAU,EAAE;IACzD,IAAI,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QACf,IAAI,CAAC;YACH,wEAAwE;YACxE,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;gBACtC,QAAQ,EAAE,EAAE;gBACZ,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,SAAS;gBAChB,GAAG,EAAE,SAAS;aACf,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,4DAA4D;YAC5D,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC;QACb,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM;QACjF,CAAC,CAAC,CAAC,CAAC;IACN,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAU,EAAU,EAAE;IACnD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;YAC7C,QAAQ,EAAE,EAAE;YACZ,YAAY,EAAE,YAAY;YAC1B,IAAI,EAAE,SAAS;SAChB,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACvE,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,EAAU,EAAU,EAAE;IACjE,MAAM,KAAK,GAA+B;QACxC,OAAO,EAAE,OAAO;QAChB,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,IAAI,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QACf,IAAI,CAAC;YACH,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtF,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC;QACb,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM;QACjF,CAAC,CAAC,CAAC,CAAC;IACN,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAClF,OAAO,GAAG,KAAK,CAChB,CAAC;IACF,OAAO,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC;AAClD,CAAC,CAAC;AAEF,qDAAqD;AACrD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAE,EAAU,EAAU,EAAE;IACzF,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9D,8EAA8E;IAC9E,oEAAoE;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,IAAI,MAAM,MAAM,EAAE,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,uFAAuF;AACvF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAiE,EACjE,KAAa,EACE,EAAE;IACjB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,0CAA0C,CAAC;IAC5E,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,2CAA2C,CAAC;IAC9E,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI,CAAC;QACR,OAAO,gFAAgF,CAAC;IAC1F,IAAI,CAAC,GAAG,UAAU;QAChB,OAAO,+BAA+B,UAAU,mCAAmC,CAAC,GAAG,CAAC;IAC1F,IAAI,IAAI,CAAC,OAAO,GAAG,KAAK;QAAE,OAAO,YAAY,IAAI,CAAC,OAAO,8BAA8B,KAAK,GAAG,CAAC;IAChG,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,cAAc;QAC9C,OAAO,yBAAyB,cAAc,gBAAgB,IAAI,CAAC,OAAO,kBAAkB,CAAC;IAC/F,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QACvE,OAAO,yDAAyD,CAAC;IACnE,IAAI,MAAM,GAAG,UAAU;QACrB,OAAO,aAAa,UAAU,+CAA+C,CAAC;IAChF,OAAO,IAAI,CAAC;AACd,CAAC,CAAC"}
|
package/dist/demo-hotels.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HotelBackend } from './backend.js';
|
|
2
|
+
import type { StateFile } from './state.js';
|
|
2
3
|
import type { Booking, ExtraKind, HotelPolicyTopic, TripLine } from './types.js';
|
|
3
4
|
/**
|
|
4
5
|
* The hotels, out of a JSON file, priced by us.
|
|
@@ -112,7 +113,7 @@ export type RawHotelData = {
|
|
|
112
113
|
membership?: RawMembership;
|
|
113
114
|
};
|
|
114
115
|
export type DemoError = Error & {
|
|
115
|
-
code: 'not-found' | 'bad-stay' | 'unavailable' | 'mixed-currency' | 'empty-trip' | 'no-guest' | 'partly-unavailable' | 'too-many-holds';
|
|
116
|
+
code: 'not-found' | 'bad-stay' | 'unavailable' | 'mixed-currency' | 'empty-trip' | 'no-guest' | 'partly-unavailable' | 'too-many-holds' | 'demo-busy';
|
|
116
117
|
};
|
|
117
118
|
export declare const demoError: (code: DemoError["code"], message: string) => DemoError;
|
|
118
119
|
export type DemoHotelsOptions = {
|
|
@@ -122,6 +123,10 @@ export type DemoHotelsOptions = {
|
|
|
122
123
|
/** Injected so tests do not depend on the day they run. */
|
|
123
124
|
now?: () => number;
|
|
124
125
|
rng?: () => number;
|
|
126
|
+
/** Where bookings and saved preferences survive a restart - none, and they stay in memory. */
|
|
127
|
+
state?: StateFile;
|
|
128
|
+
/** Room-nights all live holds together may take - see MAX_HELD_ROOM_NIGHTS. */
|
|
129
|
+
maxHeldRoomNights?: number;
|
|
125
130
|
};
|
|
126
131
|
/**
|
|
127
132
|
* A booking as this file keeps it: the booking, and the conversations that may
|
|
@@ -148,6 +153,21 @@ type StoredBooking = Booking & {
|
|
|
148
153
|
* for the two hours the holds last.
|
|
149
154
|
*/
|
|
150
155
|
export declare const MAX_HOLDS_PER_CONVERSATION = 10;
|
|
156
|
+
/**
|
|
157
|
+
* Room-nights every live hold together may take, across all conversations.
|
|
158
|
+
*
|
|
159
|
+
* ⚠️ THE CAP ABOVE IS PER CONVERSATION, AND CONVERSATIONS ARE FREE. Twelve
|
|
160
|
+
* made-up session ids, one booking each, emptied the Island Shangri-La for a
|
|
161
|
+
* month (2026-10-05 audit) - and a session id can be had from `initialize` for
|
|
162
|
+
* the asking, so checking that the id is ours raises the price of the attack
|
|
163
|
+
* from nothing to one request. What bounds the damage is this: past it, a hold
|
|
164
|
+
* is refused for everybody until some lapse, which is the demo saying "busy"
|
|
165
|
+
* rather than every room in a city saying "taken". Far above what guests and a
|
|
166
|
+
* full eval round hold together (a few dozen).
|
|
167
|
+
*/
|
|
168
|
+
export declare const MAX_HELD_ROOM_NIGHTS = 400;
|
|
169
|
+
/** A booking is kept this long after its check-out date, then forgotten - the privacy page says so. */
|
|
170
|
+
export declare const KEEP_AFTER_CHECKOUT_DAYS = 90;
|
|
151
171
|
/**
|
|
152
172
|
* A trip cut into the stays a hotel would confirm one by one: the rooms at one
|
|
153
173
|
* hotel for the same nights, and the add-ons bought for those nights.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"demo-hotels.d.ts","sourceRoot":"","sources":["../src/demo-hotels.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"demo-hotels.d.ts","sourceRoot":"","sources":["../src/demo-hotels.ts"],"names":[],"mappings":"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"}
|
package/dist/demo-hotels.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomInt, randomUUID } from 'node:crypto';
|
|
2
2
|
import { DEFAULT_PAGE, LASTING_REQUESTS, MAX_PAGE, REQUEST_KINDS, REQUEST_NOTE_MAX, } from './backend.js';
|
|
3
|
-
import { addDays, arrivalInstant, eachNight, isWeekendNight, nights as nightsBetween, stayProblem, todayAt, } from './dates.js';
|
|
3
|
+
import { addDays, arrivalInstant, atHotelTime, eachNight, isWeekendNight, nights as nightsBetween, stayProblem, todayAt, } from './dates.js';
|
|
4
4
|
import { FACILITIES, hasFacility } from './facilities.js';
|
|
5
5
|
import { addMoney, formatMoney, minorFactor, money, multiplyMoney, taxOn, toMinor, wholeUnits, } from './money.js';
|
|
6
6
|
import { MAX_EXTRA_QUANTITY, MAX_ROOMS_PER_LINE } from './trip.js';
|
|
@@ -46,6 +46,23 @@ const MAX_BOOKINGS = 5_000;
|
|
|
46
46
|
* for the two hours the holds last.
|
|
47
47
|
*/
|
|
48
48
|
export const MAX_HOLDS_PER_CONVERSATION = 10;
|
|
49
|
+
/**
|
|
50
|
+
* Room-nights every live hold together may take, across all conversations.
|
|
51
|
+
*
|
|
52
|
+
* ⚠️ THE CAP ABOVE IS PER CONVERSATION, AND CONVERSATIONS ARE FREE. Twelve
|
|
53
|
+
* made-up session ids, one booking each, emptied the Island Shangri-La for a
|
|
54
|
+
* month (2026-10-05 audit) - and a session id can be had from `initialize` for
|
|
55
|
+
* the asking, so checking that the id is ours raises the price of the attack
|
|
56
|
+
* from nothing to one request. What bounds the damage is this: past it, a hold
|
|
57
|
+
* is refused for everybody until some lapse, which is the demo saying "busy"
|
|
58
|
+
* rather than every room in a city saying "taken". Far above what guests and a
|
|
59
|
+
* full eval round hold together (a few dozen).
|
|
60
|
+
*/
|
|
61
|
+
export const MAX_HELD_ROOM_NIGHTS = 400;
|
|
62
|
+
/** A booking is kept this long after its check-out date, then forgotten - the privacy page says so. */
|
|
63
|
+
export const KEEP_AFTER_CHECKOUT_DAYS = 90;
|
|
64
|
+
/** A cancellation reason is a sentence, not a document: it is kept with the booking. */
|
|
65
|
+
const REASON_MAX = 300;
|
|
49
66
|
const publicBooking = (b) => {
|
|
50
67
|
const { owners, ...rest } = b;
|
|
51
68
|
void owners;
|
|
@@ -143,6 +160,22 @@ export const createDemoHotels = (opts) => {
|
|
|
143
160
|
const bookings = new Map();
|
|
144
161
|
/** Saved room preferences, by membership number - see `preferencesFor`. */
|
|
145
162
|
const preferences = new Map();
|
|
163
|
+
const maxHeldRoomNights = opts.maxHeldRoomNights ?? MAX_HELD_ROOM_NIGHTS;
|
|
164
|
+
const saved = opts.state?.read();
|
|
165
|
+
for (const b of saved?.bookings ?? []) {
|
|
166
|
+
if (typeof b?.id !== 'string' || typeof b.confirmationCode !== 'string')
|
|
167
|
+
continue;
|
|
168
|
+
bookings.set(b.id, { ...b, owners: new Set(Array.isArray(b.owners) ? b.owners : []) });
|
|
169
|
+
}
|
|
170
|
+
for (const [number, kinds] of saved?.preferences ?? []) {
|
|
171
|
+
if (typeof number === 'string' && Array.isArray(kinds))
|
|
172
|
+
preferences.set(number, kinds);
|
|
173
|
+
}
|
|
174
|
+
opts.state?.bind(() => ({
|
|
175
|
+
bookings: [...bookings.values()].map((b) => ({ ...b, owners: [...b.owners] })),
|
|
176
|
+
preferences: [...preferences],
|
|
177
|
+
}));
|
|
178
|
+
const changed = () => opts.state?.changed();
|
|
146
179
|
const byId = (id) => {
|
|
147
180
|
const wanted = id.trim().toLowerCase();
|
|
148
181
|
return (hotels.find((h) => h.id.toLowerCase() === wanted) ??
|
|
@@ -244,14 +277,35 @@ export const createDemoHotels = (opts) => {
|
|
|
244
277
|
}
|
|
245
278
|
return Math.max(...nights.values());
|
|
246
279
|
};
|
|
247
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* Requests that were never taken up stop holding the room, and a booking
|
|
282
|
+
* whose stay ended more than KEEP_AFTER_CHECKOUT_DAYS ago is forgotten.
|
|
283
|
+
*/
|
|
248
284
|
const sweep = () => {
|
|
249
285
|
const t = now();
|
|
250
|
-
|
|
251
|
-
|
|
286
|
+
const cutoff = new Date(t - KEEP_AFTER_CHECKOUT_DAYS * 86_400_000).toISOString().slice(0, 10);
|
|
287
|
+
let dirty = false;
|
|
288
|
+
for (const b of [...bookings.values()]) {
|
|
289
|
+
if (b.stay.checkOut < cutoff) {
|
|
290
|
+
bookings.delete(b.id);
|
|
291
|
+
dirty = true;
|
|
292
|
+
}
|
|
293
|
+
else if (b.status === 'requested' && b.holdUntil && Date.parse(b.holdUntil) <= t) {
|
|
252
294
|
b.status = 'expired';
|
|
295
|
+
dirty = true;
|
|
296
|
+
}
|
|
253
297
|
}
|
|
298
|
+
if (dirty)
|
|
299
|
+
changed();
|
|
254
300
|
};
|
|
301
|
+
/** Room-nights a booking holds - rooms times nights, line by line. */
|
|
302
|
+
const roomNightsOf = (quote, stay) => quote.lines.reduce((sum, line) => {
|
|
303
|
+
if (line.kind !== 'room')
|
|
304
|
+
return sum;
|
|
305
|
+
const held = line.stay ?? stay ?? quote.stay;
|
|
306
|
+
const nights = held ? eachNight(held.checkIn, held.checkOut).length : 0;
|
|
307
|
+
return sum + nights * (line.quantity ?? 1);
|
|
308
|
+
}, 0);
|
|
255
309
|
/**
|
|
256
310
|
* Until when this room on these nights can be cancelled for nothing - or
|
|
257
311
|
* nothing, when it cannot.
|
|
@@ -311,6 +365,9 @@ export const createDemoHotels = (opts) => {
|
|
|
311
365
|
nights: perNight.length,
|
|
312
366
|
refundable: r.refundable,
|
|
313
367
|
freeCancellationUntil: freeUntil,
|
|
368
|
+
...(freeUntil
|
|
369
|
+
? { freeCancellationLocal: atHotelTime(Date.parse(freeUntil), offsetOf(h)) }
|
|
370
|
+
: {}),
|
|
314
371
|
roomsLeft: Math.max(0, r.roomsLeft - heldOn(h.id, r.id, stay, ignore)),
|
|
315
372
|
};
|
|
316
373
|
};
|
|
@@ -414,7 +471,7 @@ export const createDemoHotels = (opts) => {
|
|
|
414
471
|
return own;
|
|
415
472
|
const email = who.email.trim().toLowerCase();
|
|
416
473
|
const there = [...bookings.values()].find((x) => x.confirmationCode.toLowerCase() === wanted && x.guest.email.trim().toLowerCase() === email);
|
|
417
|
-
if (there) {
|
|
474
|
+
if (there && !there.owners.has(who.sessionId)) {
|
|
418
475
|
there.owners.add(who.sessionId);
|
|
419
476
|
while (there.owners.size > MAX_OWNERS) {
|
|
420
477
|
const [, second] = [...there.owners];
|
|
@@ -423,6 +480,7 @@ export const createDemoHotels = (opts) => {
|
|
|
423
480
|
break;
|
|
424
481
|
there.owners.delete(second);
|
|
425
482
|
}
|
|
483
|
+
changed();
|
|
426
484
|
}
|
|
427
485
|
return there;
|
|
428
486
|
};
|
|
@@ -433,8 +491,10 @@ export const createDemoHotels = (opts) => {
|
|
|
433
491
|
for (const b of [...bookings.values()]) {
|
|
434
492
|
if (bookings.size + incoming <= MAX_BOOKINGS)
|
|
435
493
|
return;
|
|
436
|
-
if (ended(b))
|
|
494
|
+
if (ended(b)) {
|
|
437
495
|
bookings.delete(b.id);
|
|
496
|
+
changed();
|
|
497
|
+
}
|
|
438
498
|
}
|
|
439
499
|
};
|
|
440
500
|
/** A room type by its id or the name the hotel prints. */
|
|
@@ -882,7 +942,7 @@ export const createDemoHotels = (opts) => {
|
|
|
882
942
|
if (line.freeCancellationUntil && at <= Date.parse(line.freeCancellationUntil)) {
|
|
883
943
|
if (!freeUntil || line.freeCancellationUntil < freeUntil)
|
|
884
944
|
freeUntil = line.freeCancellationUntil;
|
|
885
|
-
rules.push(`${line.title} is free to cancel until ${line.freeCancellationUntil.slice(0, 16).replace('T', ' ')} UTC.`);
|
|
945
|
+
rules.push(`${line.title} is free to cancel until ${h ? `${atHotelTime(Date.parse(line.freeCancellationUntil), offsetOf(h))} hotel time` : `${line.freeCancellationUntil.slice(0, 16).replace('T', ' ')} UTC`}.`);
|
|
886
946
|
continue;
|
|
887
947
|
}
|
|
888
948
|
// A night at the booking's own average nightly rate - a stay of a
|
|
@@ -1269,8 +1329,8 @@ export const createDemoHotels = (opts) => {
|
|
|
1269
1329
|
const member = memberFor(number, surname);
|
|
1270
1330
|
if (!member)
|
|
1271
1331
|
return null;
|
|
1272
|
-
//
|
|
1273
|
-
//
|
|
1332
|
+
// Kept with the bookings (on disk when the deployment has a state
|
|
1333
|
+
// directory). The real programme keeps them on the member's profile.
|
|
1274
1334
|
const saved = preferences.get(member.number.toUpperCase());
|
|
1275
1335
|
return saved?.length ? { ...member, preferences: [...saved] } : member;
|
|
1276
1336
|
},
|
|
@@ -1280,6 +1340,7 @@ export const createDemoHotels = (opts) => {
|
|
|
1280
1340
|
preferences.set(member.number.toUpperCase(), kept);
|
|
1281
1341
|
else
|
|
1282
1342
|
preferences.delete(member.number.toUpperCase());
|
|
1343
|
+
changed();
|
|
1283
1344
|
return kept;
|
|
1284
1345
|
},
|
|
1285
1346
|
async requestBooking(trip, guest, who, requests) {
|
|
@@ -1327,6 +1388,13 @@ export const createDemoHotels = (opts) => {
|
|
|
1327
1388
|
throw demoError('too-many-holds', `Nothing was booked. This conversation already holds ${live} booking${live === 1 ? '' : 's'}, and ${MAX_HOLDS_PER_CONVERSATION} at once is the most - cancel one that is not needed, then ask again.`);
|
|
1328
1389
|
}
|
|
1329
1390
|
const quotes = await Promise.all(groups.map((g) => quoteTrip({ lines: g }, who)));
|
|
1391
|
+
const held = [...bookings.values()]
|
|
1392
|
+
.filter((b) => b.status === 'requested')
|
|
1393
|
+
.reduce((sum, b) => sum + roomNightsOf(b.quote, b.stay), 0);
|
|
1394
|
+
const asked = quotes.reduce((sum, q) => sum + roomNightsOf(q), 0);
|
|
1395
|
+
if (held + asked > maxHeldRoomNights) {
|
|
1396
|
+
throw demoError('demo-busy', 'Nothing was booked. This demonstration holds only so many rooms at once, across everybody using it, and that many are held right now; holds lapse on their own within a couple of hours. The trip is as it was - try again later.');
|
|
1397
|
+
}
|
|
1330
1398
|
const t = now();
|
|
1331
1399
|
const made = [];
|
|
1332
1400
|
for (const quote of quotes) {
|
|
@@ -1357,6 +1425,7 @@ export const createDemoHotels = (opts) => {
|
|
|
1357
1425
|
makeRoom(made.length);
|
|
1358
1426
|
for (const booking of made)
|
|
1359
1427
|
bookings.set(booking.id, booking);
|
|
1428
|
+
changed();
|
|
1360
1429
|
return made.map(publicBooking);
|
|
1361
1430
|
},
|
|
1362
1431
|
async listBookings(who, limit = 10) {
|
|
@@ -1406,6 +1475,7 @@ export const createDemoHotels = (opts) => {
|
|
|
1406
1475
|
changedAt: new Date(now()).toISOString(),
|
|
1407
1476
|
};
|
|
1408
1477
|
bookings.set(b.id, updated);
|
|
1478
|
+
changed();
|
|
1409
1479
|
return publicBooking(updated);
|
|
1410
1480
|
},
|
|
1411
1481
|
async previewCancellation(bookingRef, who) {
|
|
@@ -1444,11 +1514,13 @@ export const createDemoHotels = (opts) => {
|
|
|
1444
1514
|
b.status = 'cancelled';
|
|
1445
1515
|
b.cancelledAt = new Date(now()).toISOString();
|
|
1446
1516
|
b.cancellationFee = fee;
|
|
1447
|
-
|
|
1517
|
+
const why = reason?.replace(/\s+/g, ' ').trim().slice(0, REASON_MAX);
|
|
1518
|
+
if (why)
|
|
1448
1519
|
b.guest = {
|
|
1449
1520
|
...b.guest,
|
|
1450
|
-
notes: [b.guest.notes, `Cancelled: ${
|
|
1521
|
+
notes: [b.guest.notes, `Cancelled: ${why}`].filter(Boolean).join(' | '),
|
|
1451
1522
|
};
|
|
1523
|
+
changed();
|
|
1452
1524
|
return publicBooking(b);
|
|
1453
1525
|
},
|
|
1454
1526
|
async policies(hotelId) {
|