@curless/hotel-storefront 0.27.0 → 0.27.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.
Files changed (54) hide show
  1. package/dist/__tests__/huazhu-audit.test.js +19 -0
  2. package/dist/__tests__/huazhu-audit.test.js.map +1 -1
  3. package/dist/__tests__/huazhu-backend.test.js +510 -14
  4. package/dist/__tests__/huazhu-backend.test.js.map +1 -1
  5. package/dist/__tests__/huazhu-sandbox.test.js +1 -1
  6. package/dist/__tests__/huazhu-sandbox.test.js.map +1 -1
  7. package/dist/__tests__/server.test.js +1 -1
  8. package/dist/__tests__/server.test.js.map +1 -1
  9. package/dist/huazhu/backend.d.ts +11 -2
  10. package/dist/huazhu/backend.d.ts.map +1 -1
  11. package/dist/huazhu/backend.js +524 -271
  12. package/dist/huazhu/backend.js.map +1 -1
  13. package/dist/huazhu/bookings.d.ts +119 -9
  14. package/dist/huazhu/bookings.d.ts.map +1 -1
  15. package/dist/huazhu/bookings.js +355 -66
  16. package/dist/huazhu/bookings.js.map +1 -1
  17. package/dist/huazhu/catalog.d.ts.map +1 -1
  18. package/dist/huazhu/catalog.js +11 -1
  19. package/dist/huazhu/catalog.js.map +1 -1
  20. package/dist/huazhu/check.d.ts.map +1 -1
  21. package/dist/huazhu/check.js +19 -4
  22. package/dist/huazhu/check.js.map +1 -1
  23. package/dist/huazhu/client.d.ts +26 -0
  24. package/dist/huazhu/client.d.ts.map +1 -1
  25. package/dist/huazhu/client.js +77 -2
  26. package/dist/huazhu/client.js.map +1 -1
  27. package/dist/huazhu/fake.d.ts +12 -2
  28. package/dist/huazhu/fake.d.ts.map +1 -1
  29. package/dist/huazhu/fake.js +17 -4
  30. package/dist/huazhu/fake.js.map +1 -1
  31. package/dist/huazhu/origin.d.ts +29 -0
  32. package/dist/huazhu/origin.d.ts.map +1 -0
  33. package/dist/huazhu/origin.js +69 -0
  34. package/dist/huazhu/origin.js.map +1 -0
  35. package/dist/huazhu/sandbox.d.ts.map +1 -1
  36. package/dist/huazhu/sandbox.js +5 -1
  37. package/dist/huazhu/sandbox.js.map +1 -1
  38. package/dist/huazhu/sellable.d.ts +6 -1
  39. package/dist/huazhu/sellable.d.ts.map +1 -1
  40. package/dist/huazhu/sellable.js +14 -3
  41. package/dist/huazhu/sellable.js.map +1 -1
  42. package/dist/huazhu/wire.d.ts +28 -4
  43. package/dist/huazhu/wire.d.ts.map +1 -1
  44. package/dist/huazhu/wire.js +42 -3
  45. package/dist/huazhu/wire.js.map +1 -1
  46. package/dist/index.js +13 -5
  47. package/dist/index.js.map +1 -1
  48. package/dist/server.d.ts +7 -1
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +44 -2
  51. package/dist/server.js.map +1 -1
  52. package/dist/types.d.ts +7 -1
  53. package/dist/types.d.ts.map +1 -1
  54. package/package.json +9 -11
@@ -1,27 +1,107 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
3
  import { dirname, join } from 'node:path';
4
+ import { money, toMinor } from '../money.js';
3
5
  import { HuazhuRefusal, HuazhuUnreachable } from './client.js';
6
+ import { CODES } from './wire.js';
4
7
  /** "8分钟内不超过16次/每单". */
5
8
  export const PENDING_WINDOW_MS = 8 * 60_000;
6
9
  export const MAX_CHECKS = 16;
7
- export const CHECK_EVERY_MS = 30_000;
8
- /** Bookings over this long ago are forgotten, oldest first. */
9
- const KEEP_AFTER_CHECKOUT_MS = 90 * 86_400_000;
10
+ /** The documentation's "Reservation not found / 未找到订单" - the one answer that means "not there". */
11
+ export const NOT_FOUND = 5602;
12
+ /** The ages at which the guest's own request asks - the rest are spread over the window. */
13
+ export const IN_REQUEST_AT_MS = [5_000, 12_000, 20_000];
14
+ /** The last check of the window is this old - a little inside the eight minutes. */
15
+ const LAST_CHECK_AT_MS = PENDING_WINDOW_MS - 10_000;
16
+ /**
17
+ * A "not found" at least this old is an answer. One in the first seconds says
18
+ * only that the request has not landed YET - it may still be on its way.
19
+ */
20
+ export const LATE_FROM_MS = 6 * 60_000;
21
+ /** After the window - a process that was down through it - checks are this far apart. */
22
+ const AFTER_WINDOW_GAP_MS = 30_000;
23
+ const MIN_GAP_MS = 5_000;
24
+ /** How often the reconciler looks for a check that is due. */
25
+ export const TICK_MS = 5_000;
26
+ /** Taking back a stay: tries that got no answer before a person is asked, and the longest wait between. */
27
+ const TAKE_BACK_TRIES = 8;
28
+ const TAKE_BACK_GAP_MAX_MS = 60 * 60_000;
29
+ /** A refusal that says "not now", not "no" - the documentation's codes to retry. */
30
+ const TRANSIENT = new Set([CODES.systemError, CODES.invalidToken, CODES.rateLimited]);
31
+ const ORDER_STATUSES = new Set([
32
+ 'HOTEL_RESERVATION',
33
+ 'HOTEL_CANCEL',
34
+ 'HOTEL_ROOM_CHECK_IN',
35
+ 'HOTEL_COMPLETE',
36
+ 'HOTEL_NO_SHOW',
37
+ 'HOTEL_ROOM_CHECK_OUT',
38
+ 'HOTEL_FAILED',
39
+ ]);
40
+ /** Bookings this long after their check-out - or after a person resolved them - are forgotten. */
41
+ export const KEEP_AFTER_MS = 90 * 86_400_000;
42
+ /** The file holding everybody's bookings could not be written. */
43
+ export class StoreWriteError extends Error {
44
+ }
45
+ /** When the next consistency query about `row` is due. */
46
+ export const nextCheckAt = (row) => {
47
+ const since = row.pendingSince ?? 0;
48
+ const k = row.checks ?? 0;
49
+ const gapFrom = (row.checkedAt ?? Number.NEGATIVE_INFINITY) + MIN_GAP_MS;
50
+ const planned = IN_REQUEST_AT_MS[k];
51
+ if (planned !== undefined)
52
+ return Math.max(since + planned, gapFrom);
53
+ // ⚠️ SPREAD OVER THE WHOLE WINDOW, not front-loaded. Sixteen queries thirty
54
+ // seconds apart from the start ran out at 385 seconds and wrote the booking
55
+ // off with a minute and a half of the window unasked (2026-10-05 audit, P1-4).
56
+ const last = row.checkedAt ?? since + (IN_REQUEST_AT_MS.at(-1) ?? 0);
57
+ const end = since + LAST_CHECK_AT_MS;
58
+ if (last < end)
59
+ return Math.max(last + (end - last) / (MAX_CHECKS - k), gapFrom);
60
+ return last + AFTER_WINDOW_GAP_MS;
61
+ };
10
62
  export class BookingStore {
11
63
  now;
64
+ log;
12
65
  rows = [];
66
+ intents = [];
67
+ ceiling;
13
68
  path;
14
- constructor(stateDir, now = () => Date.now()) {
69
+ /** Why the last write failed, while it is still failing. */
70
+ failing;
71
+ /** This process. An open intent from any other one was cut short. */
72
+ boot = randomUUID();
73
+ constructor(stateDir, now = () => Date.now(), log = (l) => console.error(l)) {
15
74
  this.now = now;
75
+ this.log = log;
16
76
  this.path = join(stateDir, 'bookings.json');
77
+ // ⚠️ ONLY "NO FILE YET" IS AN EMPTY STORE. A file that could not be read
78
+ // or did not parse used to be read as empty, and the next booking wrote
79
+ // over everybody's (2026-10-05 audit, P1-8). It is left exactly where it
80
+ // is, and the connector does not start: a person looks at it first.
81
+ let text;
82
+ try {
83
+ text = readFileSync(this.path, 'utf8');
84
+ }
85
+ catch (err) {
86
+ if (err.code !== 'ENOENT') {
87
+ throw new Error(`${this.path} could not be read (${err.message}). It holds every booking made here, so the connector will not start over it - fix or move it by hand, then start again.`);
88
+ }
89
+ }
90
+ if (text === undefined)
91
+ return;
92
+ let raw;
17
93
  try {
18
- const raw = JSON.parse(readFileSync(this.path, 'utf8'));
19
- if (Array.isArray(raw?.rows))
20
- this.rows = raw.rows;
94
+ raw = JSON.parse(text);
21
95
  }
22
- catch {
23
- // None yet.
96
+ catch (err) {
97
+ throw new Error(`${this.path} is not readable JSON (${err.message}). It holds every booking made here, so the connector will not start over it - it has been left as it is: repair it, or move it aside once its bookings are accounted for, then start again.`);
24
98
  }
99
+ if (!raw || typeof raw !== 'object' || !Array.isArray(raw.rows)) {
100
+ throw new Error(`${this.path} does not hold a list of bookings. The connector will not start over it - look at it by hand, then start again.`);
101
+ }
102
+ this.rows = raw.rows;
103
+ this.intents = Array.isArray(raw.intents) ? raw.intents : [];
104
+ this.ceiling = typeof raw.ceilingHitAt === 'number' ? raw.ceilingHitAt : undefined;
25
105
  }
26
106
  all() {
27
107
  return this.rows;
@@ -29,36 +109,141 @@ export class BookingStore {
29
109
  get(id) {
30
110
  return this.rows.find((r) => r.id === id);
31
111
  }
32
- /** Written BEFORE the call that makes it real, so a crash mid-call leaves something to follow up. */
112
+ /**
113
+ * Written BEFORE the call that makes it real, so a crash mid-call leaves
114
+ * something to follow up - and so a write that fails means the call is not
115
+ * made: {@link StoreWriteError}, and the row is not kept in memory either.
116
+ */
33
117
  put(row) {
34
118
  const i = this.rows.findIndex((r) => r.id === row.id);
119
+ const before = i >= 0 ? this.rows[i] : undefined;
35
120
  if (i >= 0)
36
121
  this.rows[i] = row;
37
122
  else
38
123
  this.rows.push(row);
39
- this.save();
124
+ try {
125
+ this.save(true);
126
+ }
127
+ catch (err) {
128
+ const at = this.rows.indexOf(row);
129
+ if (at >= 0) {
130
+ if (before)
131
+ this.rows[at] = before;
132
+ else
133
+ this.rows.splice(at, 1);
134
+ }
135
+ throw new StoreWriteError(err.message);
136
+ }
40
137
  }
138
+ /**
139
+ * ⚠️ NEVER THROWS. What it records has already happened at Huazhu - a
140
+ * booking made, a cancellation done - and a failure to write it down must
141
+ * not be reported to the guest as the thing itself failing. It stays in
142
+ * memory, the failure is logged and counted as needing a person, and the
143
+ * next write that succeeds carries it.
144
+ */
41
145
  update(id, patch) {
42
146
  const row = this.get(id);
43
147
  if (!row)
44
148
  return undefined;
45
149
  Object.assign(row, patch);
46
- this.save();
150
+ this.save(false);
47
151
  return row;
48
152
  }
49
- save() {
50
- const cutoff = this.now() - KEEP_AFTER_CHECKOUT_MS;
153
+ /** A person dealt with a booking that needed one. */
154
+ resolve(id, resolution, patch = {}) {
155
+ const row = this.get(id);
156
+ if (!row)
157
+ return undefined;
158
+ return this.update(id, {
159
+ ...patch,
160
+ resolvedAt: new Date(this.now()).toISOString(),
161
+ resolution: resolution.slice(0, 500),
162
+ });
163
+ }
164
+ /** Bookings a person still has to look at. */
165
+ unresolved() {
166
+ return this.rows.filter((r) => r.attention && !r.resolvedAt);
167
+ }
168
+ // ---------------------------------------------------------- intents ----
169
+ open(intent) {
170
+ this.intents.push({ ...intent, boot: this.boot });
171
+ try {
172
+ this.save(true);
173
+ }
174
+ catch (err) {
175
+ this.intents = this.intents.filter((x) => x.tripRef !== intent.tripRef);
176
+ throw new StoreWriteError(err.message);
177
+ }
178
+ }
179
+ close(tripRef, patch = {}) {
180
+ const it = this.intents.find((x) => x.tripRef === tripRef);
181
+ if (!it)
182
+ return;
183
+ Object.assign(it, { ...patch, done: true });
184
+ this.save(false);
185
+ }
186
+ /** Requests an earlier process left open. */
187
+ orphans() {
188
+ return this.intents.filter((x) => !x.done && x.boot !== this.boot);
189
+ }
190
+ intent(tripRef) {
191
+ return this.intents.find((x) => x.tripRef === tripRef);
192
+ }
193
+ // ---------------------------------------------------------- ceiling ----
194
+ /** When the deployment's daily ceiling last turned a booking away - kept across a restart. */
195
+ get ceilingHitAt() {
196
+ return this.ceiling;
197
+ }
198
+ set ceilingHitAt(at) {
199
+ this.ceiling = at;
200
+ this.save(false);
201
+ }
202
+ /** Why writing is failing, while it is. */
203
+ get writeFailing() {
204
+ return this.failing;
205
+ }
206
+ save(strict) {
207
+ const cutoff = this.now() - KEEP_AFTER_MS;
208
+ const after = (iso) => (iso ? Date.parse(iso) > cutoff : false);
51
209
  this.rows = this.rows.filter((r) => r.pendingSince !== undefined ||
52
- !!r.attention ||
210
+ (!!r.attention && !r.resolvedAt) ||
211
+ after(r.resolvedAt) ||
53
212
  Date.parse(`${r.stay.checkOut}T00:00:00Z`) > cutoff);
54
- mkdirSync(dirname(this.path), { recursive: true });
55
- const tmp = `${this.path}.${process.pid}.tmp`;
56
- writeFileSync(tmp, JSON.stringify({ rows: this.rows }));
57
- renameSync(tmp, this.path);
213
+ const live = new Set(this.rows.map((r) => r.tripRef));
214
+ this.intents = this.intents.filter((x) => !x.done || live.has(x.tripRef));
215
+ try {
216
+ mkdirSync(dirname(this.path), { recursive: true });
217
+ const tmp = `${this.path}.${process.pid}.tmp`;
218
+ // 0600, as every other state file: names, emails and phone numbers.
219
+ writeFileSync(tmp, JSON.stringify({
220
+ rows: this.rows,
221
+ intents: this.intents,
222
+ ...(this.ceiling !== undefined ? { ceilingHitAt: this.ceiling } : {}),
223
+ }), { mode: 0o600 });
224
+ renameSync(tmp, this.path);
225
+ if (this.failing)
226
+ this.log(`[huazhu bookings] ${this.path} is being written again`);
227
+ this.failing = undefined;
228
+ }
229
+ catch (err) {
230
+ const why = err.message;
231
+ if (this.failing === undefined)
232
+ this.log(`[huazhu bookings] ⚠️ NEEDS A PERSON: ${this.path} could not be written (${why}) - bookings are kept in memory until it can be, and a restart now would lose them`);
233
+ this.failing = why;
234
+ if (strict)
235
+ throw err;
236
+ }
58
237
  }
59
238
  }
60
239
  /** Huazhu's word → the connector's. Checked in, checked out and no-show are all a booking that happened. */
61
240
  export const statusOf = (s) => s === 'HOTEL_CANCEL' ? 'cancelled' : s === 'HOTEL_FAILED' ? 'failed' : 'confirmed';
241
+ /** An answer to the consistency query that actually says something. */
242
+ const said = (x) => !!x &&
243
+ typeof x.status === 'string' &&
244
+ ORDER_STATUSES.has(x.status) &&
245
+ // "Failed" needs no order number; anything else that has none is not an answer.
246
+ (x.status === 'HOTEL_FAILED' || (typeof x.resId === 'string' && x.resId.length > 0));
62
247
  /**
63
248
  * Follows up every booking whose outcome is unknown, on the documentation's
64
249
  * schedule, and takes back a trip's other stays when one of them failed.
@@ -79,7 +264,7 @@ export class Reconciler {
79
264
  start() {
80
265
  if (this.timer)
81
266
  return;
82
- this.timer = setInterval(() => void this.tick(), CHECK_EVERY_MS);
267
+ this.timer = setInterval(() => void this.tick(), TICK_MS);
83
268
  this.timer.unref?.();
84
269
  void this.tick();
85
270
  }
@@ -97,69 +282,128 @@ export class Reconciler {
97
282
  }
98
283
  return this.running;
99
284
  }
100
- /** Ask once about one booking; true when its outcome is now known. */
101
- async check(row) {
285
+ /** Whether the follow-up of `row` has what it needs for a verdict. */
286
+ decided(row) {
102
287
  if (row.pendingSince === undefined)
103
288
  return true;
104
- const age = this.now() - row.pendingSince;
105
- if (age > PENDING_WINDOW_MS || (row.checks ?? 0) >= MAX_CHECKS) {
106
- if ((row.unreachableChecks ?? 0) > 0) {
107
- // The follow-up itself could not get through: nobody knows, and the
108
- // documentation gives a person 24 hours to find out with Huazhu.
109
- this.flag(row, `the booking call and ${row.unreachableChecks} of its follow-up queries went unanswered - confirm distributorResId ${row.distributorResId} with Huazhu within 24 hours of ${new Date(row.pendingSince).toISOString()}`);
110
- this.store.update(row.id, { pendingSince: undefined, status: 'failed' });
111
- }
112
- else {
113
- // Eight minutes of clean "not found": by rule, it failed.
114
- this.store.update(row.id, {
115
- pendingSince: undefined,
116
- status: 'failed',
117
- hotelStatus: 'HOTEL_FAILED',
118
- });
119
- }
289
+ if (this.now() - row.pendingSince < PENDING_WINDOW_MS)
290
+ return false;
291
+ return row.lateMissAt !== undefined || (row.checks ?? 0) >= MAX_CHECKS;
292
+ }
293
+ /** Whether `row` should be looked at now. */
294
+ due(row) {
295
+ return row.pendingSince !== undefined && (this.decided(row) || this.now() >= nextCheckAt(row));
296
+ }
297
+ /**
298
+ * Ask once about one booking - or, once the window has what it needs, give
299
+ * the verdict. True when its outcome is now known.
300
+ */
301
+ async check(row) {
302
+ const current = this.store.get(row.id) ?? row;
303
+ if (current.pendingSince === undefined)
304
+ return true;
305
+ const since = current.pendingSince;
306
+ if (this.decided(current)) {
307
+ // ⚠️ ONLY A LATE "NOT FOUND" WRITES IT OFF. Eight minutes of anything
308
+ // else - no answer, "too many requests", a restart that asked nothing at
309
+ // all - used to be read as "failed", and a booking Huazhu had made was
310
+ // left with the hotel and shown nowhere (2026-10-05 audit, P1-1).
311
+ if (current.lateMissAt !== undefined)
312
+ this.writeOff(current);
313
+ else
314
+ this.unconfirmed(current, since);
120
315
  return true;
121
316
  }
122
- this.store.update(row.id, { checks: (row.checks ?? 0) + 1 });
317
+ const at = this.now();
318
+ this.store.update(current.id, { checks: (current.checks ?? 0) + 1, checkedAt: at });
319
+ let found;
123
320
  try {
124
- const found = await this.client.consistency(row.distributorResId);
125
- const status = statusOf(found.status);
126
- this.store.update(row.id, {
127
- pendingSince: undefined,
128
- resId: found.resId || row.resId,
129
- ...(found.resId ? { confirmationCode: found.resId } : {}),
130
- hotelStatus: found.status,
131
- status,
132
- });
133
- if (status === 'confirmed' && row.rollback)
134
- await this.takeBack(row);
135
- return true;
321
+ found = await this.client.consistency(current.distributorResId);
136
322
  }
137
323
  catch (err) {
138
- if (err instanceof HuazhuUnreachable) {
139
- this.store.update(row.id, { unreachableChecks: (row.unreachableChecks ?? 0) + 1 });
324
+ if (err instanceof HuazhuRefusal && err.code === NOT_FOUND) {
325
+ if (at - since >= LATE_FROM_MS) {
326
+ this.store.update(current.id, { lateMissAt: at });
327
+ // Asked after the window (a process that was down through it): that
328
+ // late, "not found" is the answer.
329
+ if (at - since >= PENDING_WINDOW_MS) {
330
+ this.writeOff(current);
331
+ return true;
332
+ }
333
+ }
334
+ return false;
140
335
  }
141
- // "Not found" is not an answer yet: the request may still be on its way.
336
+ // Anything else - no answer, "too many requests", a system error -
337
+ // says nothing about the booking.
338
+ this.store.update(current.id, {
339
+ unreachableChecks: (current.unreachableChecks ?? 0) + 1,
340
+ });
142
341
  return false;
143
342
  }
343
+ if (!said(found)) {
344
+ this.store.update(current.id, {
345
+ unreachableChecks: (current.unreachableChecks ?? 0) + 1,
346
+ });
347
+ return false;
348
+ }
349
+ const status = statusOf(found.status);
350
+ this.store.update(current.id, {
351
+ pendingSince: undefined,
352
+ ...(found.resId ? { resId: found.resId } : {}),
353
+ hotelStatus: found.status,
354
+ status,
355
+ ...(status === 'failed' ? { rollback: false } : {}),
356
+ });
357
+ if (status === 'confirmed' && current.rollback)
358
+ await this.takeBack(current);
359
+ return true;
360
+ }
361
+ /** Eight minutes and a late "not found": by rule, it failed. */
362
+ writeOff(row) {
363
+ this.store.update(row.id, {
364
+ pendingSince: undefined,
365
+ status: 'failed',
366
+ hotelStatus: 'HOTEL_FAILED',
367
+ rollback: false,
368
+ });
144
369
  }
145
- /** Cancel a booking whose trip did not go through as a whole. */
370
+ /** Nobody knows - the documentation gives a person 24 hours to find out with Huazhu. */
371
+ unconfirmed(row, since) {
372
+ this.store.update(row.id, { pendingSince: undefined, status: 'unconfirmed' });
373
+ const asked = row.checks ?? 0;
374
+ const unanswered = row.unreachableChecks ?? 0;
375
+ this.flag(row, `the booking call went unanswered and ${asked} follow-up ${asked === 1 ? 'query' : 'queries'} (${unanswered} without an answer) never had Huazhu say late in the eight minutes that it does not exist - confirm distributorResId ${row.distributorResId} with Huazhu within 24 hours of ${new Date(since).toISOString()}${row.rollback ? ', and cancel it if it exists: its trip failed' : ''}`);
376
+ }
377
+ /**
378
+ * Cancel a booking whose trip did not go through as a whole. A "no" stops
379
+ * at once and asks for a person; no answer is tried again, further apart
380
+ * each time, and asks for a person after {@link TAKE_BACK_TRIES} - never
381
+ * forever (2026-10-05 audit, e13: every 30 seconds, for good).
382
+ */
146
383
  async takeBack(row) {
147
- const resId = this.store.get(row.id)?.resId ?? row.resId;
148
- if (!resId)
384
+ const current = this.store.get(row.id) ?? row;
385
+ const resId = current.resId;
386
+ if (!resId || !current.rollback)
387
+ return;
388
+ if (current.takeBackAt !== undefined && this.now() < current.takeBackAt)
149
389
  return;
150
390
  try {
151
391
  const out = await this.client.cancel(resId);
392
+ const penalty = typeof out?.penaltyAmount === 'number' && out.penaltyAmount > 0
393
+ ? `${out.penaltyAmount} ${out.penaltyCurrencyCode ?? ''}`.trim()
394
+ : undefined;
395
+ const cur = out?.penaltyCurrencyCode || current.quote.total.currency;
152
396
  this.store.update(row.id, {
153
397
  status: 'cancelled',
154
398
  hotelStatus: 'HOTEL_CANCEL',
155
399
  cancelledAt: new Date(this.now()).toISOString(),
156
400
  rollback: false,
157
- ...(typeof out.penaltyAmount === 'number' && out.penaltyAmount > 0
158
- ? {
159
- attention: `taken back after its trip failed, and Huazhu charged a penalty of ${out.penaltyAmount} ${out.penaltyCurrencyCode ?? ''}`,
160
- }
161
- : {}),
401
+ takeBackAt: undefined,
402
+ // Said to the guest with the trip's failure - see `takeBackAll`.
403
+ ...(penalty ? { cancellationFee: money(toMinor(out.penaltyAmount ?? 0, cur), cur) } : {}),
162
404
  });
405
+ if (penalty)
406
+ this.flag(row, `taken back after its trip failed, and Huazhu charged a penalty of ${penalty}`);
163
407
  }
164
408
  catch (err) {
165
409
  if (err instanceof HuazhuRefusal && err.code === 5402) {
@@ -167,21 +411,66 @@ export class Reconciler {
167
411
  status: 'cancelled',
168
412
  hotelStatus: 'HOTEL_CANCEL',
169
413
  rollback: false,
414
+ takeBackAt: undefined,
170
415
  });
171
416
  return;
172
417
  }
173
- this.flag(row, `its trip failed and it could not be taken back (${err.message}) - cancel resId ${resId} by hand`);
418
+ const transient = !(err instanceof HuazhuRefusal) || TRANSIENT.has(err.code);
419
+ const tries = (current.takeBackTries ?? 0) + 1;
420
+ if (transient && tries < TAKE_BACK_TRIES) {
421
+ this.store.update(row.id, {
422
+ takeBackTries: tries,
423
+ takeBackAt: this.now() + Math.min(30_000 * 2 ** tries, TAKE_BACK_GAP_MAX_MS),
424
+ });
425
+ return;
426
+ }
427
+ this.store.update(row.id, { rollback: false, takeBackTries: tries, takeBackAt: undefined });
428
+ this.flag(row, `its trip failed and it could not be taken back (${err.message}${transient ? `, ${tries} tries` : ''}) - cancel resId ${resId} by hand`);
429
+ }
430
+ }
431
+ /**
432
+ * Requests an earlier process died in the middle of: all or nothing. Every
433
+ * stay booked → the trip stands; anything short of that → what was booked
434
+ * is taken back, and a stay whose outcome is unknown is taken back if it
435
+ * turns up.
436
+ */
437
+ async recover() {
438
+ for (const it of this.store.orphans()) {
439
+ const rows = this.store.all().filter((r) => r.tripRef === it.tripRef);
440
+ const whole = rows.length === it.stays && rows.every((r) => r.status === 'confirmed' && !r.rollback);
441
+ if (whole) {
442
+ this.store.close(it.tripRef);
443
+ continue;
444
+ }
445
+ for (const r of rows) {
446
+ if (r.status === 'failed' || r.status === 'cancelled')
447
+ continue;
448
+ this.store.update(r.id, { rollback: true });
449
+ }
450
+ this.store.close(it.tripRef, { cutShort: true });
451
+ this.log(`[huazhu trip ${it.tripRef}] cut short by a restart with ${rows.length} of ${it.stays} stays asked for - taking back what it booked`);
452
+ for (const r of rows) {
453
+ const now = this.store.get(r.id);
454
+ if (now?.rollback && now.status === 'confirmed')
455
+ await this.takeBack(now);
456
+ }
174
457
  }
175
458
  }
176
459
  flag(row, why) {
177
- this.store.update(row.id, { attention: why });
460
+ this.store.update(row.id, {
461
+ attention: why,
462
+ attentionAt: new Date(this.now()).toISOString(),
463
+ resolvedAt: undefined,
464
+ resolution: undefined,
465
+ });
178
466
  this.log(`[huazhu booking ${row.id}] ⚠️ NEEDS A PERSON: ${why}`);
179
467
  }
180
468
  async pass() {
469
+ await this.recover();
181
470
  for (const row of [...this.store.all()]) {
182
- if (row.pendingSince !== undefined)
471
+ if (this.due(row))
183
472
  await this.check(row);
184
- else if (row.rollback && row.status === 'confirmed')
473
+ else if (row.pendingSince === undefined && row.rollback && row.status === 'confirmed')
185
474
  await this.takeBack(row);
186
475
  }
187
476
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bookings.js","sourceRoot":"","sources":["../../src/huazhu/bookings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bookings.js","sourceRoot":"","sources":["../../src/huazhu/bookings.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/huazhu/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/huazhu/catalog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAA4C,KAAK,WAAW,EAAY,MAAM,WAAW,CAAC;AAkBjG,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAeF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAIF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,aAAa,QAAS,CAAC;AAEpC,qBAAa,OAAO;IAcN,OAAO,CAAC,QAAQ,CAAC,IAAI;IAbjC,OAAO,CAAC,IAAI,CAAsD;IAClE,OAAO,CAAC,OAAO,CAAC,CAAgB;IAChC,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,kEAAkE;IAClE,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,OAAO,CAAK;IACpB;;;OAGG;IACH,OAAO,CAAC,OAAO,CAAK;gBAES,IAAI,EAAE,cAAc;IAUjD,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,GAAG;IAIX,mDAAmD;IACnD,GAAG,IAAI,WAAW,EAAE;IAMpB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIxC,6DAA6D;IAC7D,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,KAAK,IAAI,YAAY;IAUrB,sFAAsF;IACtF,KAAK,IAAI,OAAO;IAUhB,8DAA8D;IAC9D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IASrB,qCAAqC;IACrC,OAAO,CAAC,KAAK;IAKb,0FAA0F;IAC1F,OAAO,CAAC,QAAQ;IAQhB,uDAAuD;IACvD,OAAO,CAAC,WAAW;IAInB,sFAAsF;IACtF,IAAI,MAAM,IAAI,MAAM,CAEnB;IACD,OAAO,CAAC,OAAO,CAAK;IAEpB,OAAO,CAAC,IAAI;YAUE,GAAG;CAgGlB;AAID,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,MAAM,GAAI,GAAG,WAAW,KAAG,MAGvC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,GAAG,WAAW,KAAG,MACmC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAMzD,CAAC;AAKF,6FAA6F;AAC7F,eAAO,MAAM,SAAS,GAAI,GAAG,WAAW,KAAG,MAAM,GAAG,SAQnD,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,SAAS,GAAI,GAAG,WAAW,EAAE,cAAc,MAAM,KAAG,MAAM,GAAG,SAOvE,CAAC;AAIJ,2DAA2D;AAC3D,eAAO,MAAM,OAAO,GAAI,GAAG,WAAW,EAAE,GAAG,WAAW,EAAE,KAAK,MAAM,KAAG,KA0BrE,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,KAAG,MAiB1B,CAAC;AAQnB;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,GAAG,WAAW,EAAE,OAAO,MAAM,KAAG,OASvD,CAAC"}
@@ -139,7 +139,17 @@ export class Catalog {
139
139
  }
140
140
  }
141
141
  const wanted = this.opts.only?.length ? new Set(this.opts.only.map(String)) : undefined;
142
- const ids = [...new Set(listed.map((h) => String(h.hotelId)))].filter((id) => !wanted || wanted.has(id));
142
+ const ids = [...new Set((listed ?? []).map((h) => String(h.hotelId)))].filter((id) => !wanted || wanted.has(id));
143
+ // ⚠️ AN EMPTY LIST NEVER EMPTIES THE COPY. Huazhu ending every contract at
144
+ // once is not what an empty answer means; a fault on its side is - and
145
+ // taken at its word, one empty answer took every hotel off the connector
146
+ // until the next day's sync (2026-10-05 audit, e14). The copy is kept,
147
+ // and the list is asked for again at the next hourly look.
148
+ if (ids.length === 0 && Object.keys(this.file.hotels).length > 0) {
149
+ this.stoppedBecause = `the hotel list came back empty with ${Object.keys(this.file.hotels).length} hotel(s) in the copy - kept, and asked for again at the next sync`;
150
+ this.log(this.stoppedBecause);
151
+ return;
152
+ }
143
153
  // ⚠️ OFF THE LIST IS OFF THE CONNECTOR, now - not after its record ages out.
144
154
  const keep = new Set(ids);
145
155
  const gone = Object.keys(this.file.hotels).filter((id) => !keep.has(id));