kaafil-js 0.1.0-beta.3 → 0.1.0-beta.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.
@@ -144,6 +144,7 @@ var OPERATION_SECURITY = {
144
144
  createRoomingRoom: ["managerAuth"],
145
145
  createRoomingStayWindow: ["managerAuth"],
146
146
  createSeatingVehicle: ["managerAuth"],
147
+ createSupportGrant: ["platformAdminAuth"],
147
148
  createTrekWalkIn: ["managerAuth"],
148
149
  deleteBooking: ["apiKeyAuth"],
149
150
  deleteChecklistItem: ["managerAuth"],
@@ -158,8 +159,10 @@ var OPERATION_SECURITY = {
158
159
  deleteSeatingVehicle: ["managerAuth"],
159
160
  dispatchForm: ["managerAuth", "apiKeyAuth"],
160
161
  editWebhookEndpoint: ["consoleAuth"],
162
+ eraseTraveller: ["apiKeyAuth"],
161
163
  exportCloseoutPack: ["managerAuth", "apiKeyAuth"],
162
164
  exportFormResponses: ["apiKeyAuth", "managerAuth"],
165
+ exportTraveller: ["apiKeyAuth"],
163
166
  getForm: ["apiKeyAuth", "agencyAdminAuth", "managerAuth"],
164
167
  getFormAggregate: ["apiKeyAuth"],
165
168
  getFormConsentReceipt: ["apiKeyAuth", "managerAuth"],
@@ -198,6 +201,8 @@ var OPERATION_SECURITY = {
198
201
  listPlatformPartnerConsoleUsers: ["platformAdminAuth"],
199
202
  listPlatformPartners: ["platformAdminAuth"],
200
203
  listRoomingStayWindows: ["managerAuth", "agencyAdminAuth", "apiKeyAuth"],
204
+ listSupportIngestLog: ["platformAdminAuth"],
205
+ listSupportWebhookDeliveries: ["platformAdminAuth"],
201
206
  listTripFormResponses: ["managerAuth", "apiKeyAuth"],
202
207
  listTripForms: ["managerAuth", "apiKeyAuth"],
203
208
  listTripVendors: ["apiKeyAuth", "managerAuth", "agencyAdminAuth"],
@@ -271,6 +276,8 @@ var OPERATION_SECURITY = {
271
276
  readRoomingBoard: ["managerAuth", "agencyAdminAuth", "apiKeyAuth"],
272
277
  readSeatingBoard: ["managerAuth", "agencyAdminAuth", "apiKeyAuth"],
273
278
  readShareToken: ["apiKeyAuth"],
279
+ readSupportJourneyState: ["platformAdminAuth"],
280
+ readSupportWebhookDeliveryDetail: ["platformAdminAuth"],
274
281
  readTrekBoard: ["managerAuth", "apiKeyAuth"],
275
282
  readTrekWalkInMeta: ["managerAuth", "apiKeyAuth"],
276
283
  readTripFeedbackSummary: ["managerAuth", "agencyAdminAuth", "apiKeyAuth"],
@@ -281,6 +288,7 @@ var OPERATION_SECURITY = {
281
288
  recordCollection: ["managerAuth"],
282
289
  redeliverEndpointDelivery: ["consoleAuth"],
283
290
  redeliverWebhookDelivery: ["apiKeyAuth"],
291
+ redriveSupportWebhookDelivery: ["platformAdminAuth"],
284
292
  refreshAgencyAdminTokens: ["agencyAdminAuth"],
285
293
  refreshManagerTokens: ["managerAuth"],
286
294
  regenerateShareToken: ["apiKeyAuth"],
@@ -296,6 +304,7 @@ var OPERATION_SECURITY = {
296
304
  reorderItineraryItem: ["managerAuth"],
297
305
  reorderPickupStops: ["managerAuth"],
298
306
  replaceBookingVouchers: ["apiKeyAuth"],
307
+ replaySupportWebhookRange: ["platformAdminAuth"],
299
308
  replayWebhookEndpoint: ["apiKeyAuth"],
300
309
  requestFileUpload: ["managerAuth", "apiKeyAuth"],
301
310
  resetPlatformPartnerConsoleUser: ["platformAdminAuth"],
@@ -369,6 +378,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
369
378
  createRoomingRoom: true,
370
379
  createRoomingStayWindow: true,
371
380
  createSeatingVehicle: true,
381
+ createSupportGrant: false,
372
382
  createTrekWalkIn: true,
373
383
  deleteBooking: true,
374
384
  deleteChecklistItem: false,
@@ -383,8 +393,10 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
383
393
  deleteSeatingVehicle: false,
384
394
  dispatchForm: true,
385
395
  editWebhookEndpoint: true,
396
+ eraseTraveller: true,
386
397
  exportCloseoutPack: false,
387
398
  exportFormResponses: false,
399
+ exportTraveller: false,
388
400
  getForm: false,
389
401
  getFormAggregate: false,
390
402
  getFormConsentReceipt: false,
@@ -423,6 +435,8 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
423
435
  listPlatformPartnerConsoleUsers: false,
424
436
  listPlatformPartners: false,
425
437
  listRoomingStayWindows: false,
438
+ listSupportIngestLog: false,
439
+ listSupportWebhookDeliveries: false,
426
440
  listTripFormResponses: false,
427
441
  listTripForms: false,
428
442
  listTripVendors: false,
@@ -496,6 +510,8 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
496
510
  readRoomingBoard: false,
497
511
  readSeatingBoard: false,
498
512
  readShareToken: false,
513
+ readSupportJourneyState: false,
514
+ readSupportWebhookDeliveryDetail: false,
499
515
  readTrekBoard: false,
500
516
  readTrekWalkInMeta: false,
501
517
  readTripFeedbackSummary: false,
@@ -506,6 +522,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
506
522
  recordCollection: true,
507
523
  redeliverEndpointDelivery: true,
508
524
  redeliverWebhookDelivery: true,
525
+ redriveSupportWebhookDelivery: false,
509
526
  refreshAgencyAdminTokens: false,
510
527
  refreshManagerTokens: false,
511
528
  regenerateShareToken: true,
@@ -521,6 +538,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
521
538
  reorderItineraryItem: true,
522
539
  reorderPickupStops: true,
523
540
  replaceBookingVouchers: false,
541
+ replaySupportWebhookRange: false,
524
542
  replayWebhookEndpoint: true,
525
543
  requestFileUpload: true,
526
544
  resetPlatformPartnerConsoleUser: false,
@@ -594,6 +612,7 @@ var KaafilErrorCode = {
594
612
  StayWindowOverlap: "STAY_WINDOW_OVERLAP",
595
613
  StopHasPending: "STOP_HAS_PENDING",
596
614
  SubjectRequired: "SUBJECT_REQUIRED",
615
+ SupportGrantRequired: "SUPPORT_GRANT_REQUIRED",
597
616
  SyncTargetRefused: "SYNC_TARGET_REFUSED",
598
617
  TenantScopeMissing: "TENANT_SCOPE_MISSING",
599
618
  Unauthenticated: "UNAUTHENTICATED",
@@ -647,6 +666,7 @@ var ERROR_CODE_TABLE = {
647
666
  STAY_WINDOW_OVERLAP: { status: 422, retryability: "no", outboxClass: "FATAL" },
648
667
  STOP_HAS_PENDING: { status: 422, retryability: "no", outboxClass: "FATAL" },
649
668
  SUBJECT_REQUIRED: { status: 422, retryability: "no", outboxClass: "FATAL" },
669
+ SUPPORT_GRANT_REQUIRED: { status: 403, retryability: "no", outboxClass: "FATAL" },
650
670
  SYNC_TARGET_REFUSED: { status: 422, retryability: "no", outboxClass: "FATAL" },
651
671
  TENANT_SCOPE_MISSING: { status: 500, retryability: "yes", outboxClass: "TRANSIENT" },
652
672
  UNAUTHENTICATED: { status: 401, retryability: "after-refresh", outboxClass: "FATAL" },
@@ -1919,6 +1939,10 @@ var OutboxStatus = {
1919
1939
  /** Terminal success. Pruned on the next persist. */
1920
1940
  Done: "done"
1921
1941
  };
1942
+ var OutboxRetryCause = {
1943
+ Transport: "transport",
1944
+ Server: "server"
1945
+ };
1922
1946
  function createOutbox(options) {
1923
1947
  const key = `${options.keyPrefix}:outbox`;
1924
1948
  const mintId = options.newId ?? newIdempotencyKey;
@@ -1985,6 +2009,7 @@ function createOutbox(options) {
1985
2009
  status: OutboxStatus.Pending,
1986
2010
  attemptCount: 0,
1987
2011
  nextRetryAt: null,
2012
+ retryCause: void 0,
1988
2013
  refreshAttempted: false,
1989
2014
  parkReason: void 0
1990
2015
  };
@@ -2038,19 +2063,39 @@ function createOutbox(options) {
2038
2063
  status: OutboxStatus.Parked,
2039
2064
  parkReason: reason,
2040
2065
  attemptCount: (op?.attemptCount ?? 0) + 1,
2041
- nextRetryAt: null
2066
+ nextRetryAt: null,
2067
+ retryCause: void 0
2042
2068
  });
2043
2069
  },
2044
- async scheduleRetry(opId, nextRetryAt) {
2070
+ async scheduleRetry(opId, nextRetryAt, cause) {
2045
2071
  const op = ops.get(opId);
2046
2072
  await mutate(opId, {
2047
2073
  status: OutboxStatus.Pending,
2048
2074
  attemptCount: (op?.attemptCount ?? 0) + 1,
2049
- nextRetryAt
2075
+ nextRetryAt,
2076
+ retryCause: cause
2050
2077
  });
2051
2078
  },
2079
+ async clearTransportBackoff() {
2080
+ let cleared = 0;
2081
+ for (const [id, op] of ops) {
2082
+ if (op.status !== OutboxStatus.Pending || op.nextRetryAt === null || op.retryCause !== OutboxRetryCause.Transport) {
2083
+ continue;
2084
+ }
2085
+ ops.set(id, { ...op, nextRetryAt: null, retryCause: void 0 });
2086
+ cleared += 1;
2087
+ }
2088
+ if (cleared > 0) {
2089
+ await persist();
2090
+ }
2091
+ return cleared;
2092
+ },
2052
2093
  async requeue(opId) {
2053
- await mutate(opId, { status: OutboxStatus.Pending });
2094
+ await mutate(opId, {
2095
+ status: OutboxStatus.Pending,
2096
+ nextRetryAt: null,
2097
+ retryCause: void 0
2098
+ });
2054
2099
  },
2055
2100
  async markRefreshAttempted(opId) {
2056
2101
  await mutate(opId, { refreshAttempted: true });
@@ -2064,6 +2109,7 @@ function createOutbox(options) {
2064
2109
  ...op,
2065
2110
  status: OutboxStatus.Pending,
2066
2111
  nextRetryAt: null,
2112
+ retryCause: void 0,
2067
2113
  attemptCount: op.attemptCount + 1,
2068
2114
  ...patch.body !== void 0 ? { body: patch.body } : {},
2069
2115
  ...patch.ifMatch !== void 0 ? { ifMatch: patch.ifMatch } : {}
@@ -2168,6 +2214,7 @@ function createDrainer(options) {
2168
2214
  const now = options.now ?? Date.now;
2169
2215
  const random = options.random ?? Math.random;
2170
2216
  let inFlight = null;
2217
+ const ownSignal = new AbortController();
2171
2218
  function observeServerTime(outcome) {
2172
2219
  if (outcome.serverTime !== void 0) {
2173
2220
  options.onServerTime?.(outcome.serverTime);
@@ -2246,7 +2293,11 @@ function createDrainer(options) {
2246
2293
  ...outcome.retryAfterSeconds !== void 0 ? { retryAfterSeconds: outcome.retryAfterSeconds } : {},
2247
2294
  random
2248
2295
  });
2249
- await outbox.scheduleRetry(op.id, now() + delay);
2296
+ await outbox.scheduleRetry(
2297
+ op.id,
2298
+ now() + delay,
2299
+ outcome.status === null ? OutboxRetryCause.Transport : OutboxRetryCause.Server
2300
+ );
2250
2301
  events.emit("sync.error", {
2251
2302
  opId: op.id,
2252
2303
  tripRef: op.tripRef,
@@ -2342,12 +2393,14 @@ function createDrainer(options) {
2342
2393
  let outcomes;
2343
2394
  try {
2344
2395
  outcomes = await sendBatch(ready, signal);
2345
- } catch {
2396
+ } catch (error) {
2397
+ const cause = isKaafilLike(error) && error.kind === "transport" ? OutboxRetryCause.Transport : OutboxRetryCause.Server;
2346
2398
  const [head, ...rest] = ready;
2347
2399
  if (head !== void 0) {
2348
2400
  await outbox.scheduleRetry(
2349
2401
  head.id,
2350
- now() + computeRetryDelayMs(head.attemptCount + 1, { random })
2402
+ now() + computeRetryDelayMs(head.attemptCount + 1, { random }),
2403
+ cause
2351
2404
  );
2352
2405
  }
2353
2406
  for (const op of rest) {
@@ -2399,20 +2452,68 @@ function createDrainer(options) {
2399
2452
  });
2400
2453
  return report;
2401
2454
  }
2455
+ let kickTimer;
2456
+ let pendingKickRestored = false;
2402
2457
  const drainer = {
2403
2458
  async drain(drainOptions = {}) {
2404
2459
  if (inFlight !== null) {
2405
2460
  return inFlight;
2406
2461
  }
2407
- const pass = runPass(drainOptions.signal).finally(() => {
2462
+ const signal = drainOptions.signal ?? ownSignal.signal;
2463
+ const pass = (async () => {
2464
+ if (drainOptions.connectivityRestored === true) {
2465
+ await outbox.clearTransportBackoff();
2466
+ }
2467
+ return runPass(signal);
2468
+ })().finally(() => {
2408
2469
  inFlight = null;
2409
2470
  });
2410
2471
  inFlight = pass;
2411
2472
  return pass;
2412
2473
  },
2413
- kick() {
2414
- void drainer.drain().catch(() => {
2415
- });
2474
+ // Deferred to a fresh macrotask, on purpose. `enqueue()` calls this after
2475
+ // EVERY write, and a caller enqueueing several writes in a row (a batch
2476
+ // import, this SDK's own offline smoke test, `06`'s worked example) does
2477
+ // so as a sequence of awaited calls with no real I/O between them —
2478
+ // which means their continuations are all still microtasks. A `kick()`
2479
+ // that started draining synchronously would mark the FIRST op of the
2480
+ // burst `inflight` before the caller's loop even reaches its second
2481
+ // iteration, so `outbox.counts().pending` would under-report a queue
2482
+ // that is, in fact, completely durable (`./outbox.ts`'s promise is about
2483
+ // durability, not about `pending` never dipping). Parking the kick
2484
+ // behind a macrotask lets the whole synchronous burst finish enqueueing
2485
+ // — and, for a real UI, the current paint — before the drain takes its
2486
+ // first op off the pending list. Nothing about durability changes: the
2487
+ // write-ahead persist in `enqueue()` already happened before this method
2488
+ // is even called.
2489
+ kick(kickOptions = {}) {
2490
+ if (kickTimer !== void 0) {
2491
+ pendingKickRestored = pendingKickRestored || kickOptions.connectivityRestored === true;
2492
+ return;
2493
+ }
2494
+ pendingKickRestored = kickOptions.connectivityRestored === true;
2495
+ kickTimer = setTimeout(() => {
2496
+ kickTimer = void 0;
2497
+ const restored = pendingKickRestored;
2498
+ pendingKickRestored = false;
2499
+ void drainer.drain({ connectivityRestored: restored }).catch(() => {
2500
+ });
2501
+ }, 0);
2502
+ },
2503
+ // Called only from `OfflineEngine.close()` (`./engine.ts`). Two separate
2504
+ // handles, both cleared: a `kick()` that is scheduled but has not fired
2505
+ // yet (the `setTimeout` itself), and a pass already running under
2506
+ // `ownSignal` — which, per `drain()` above, is every automatic kick and
2507
+ // any signal-less explicit call. Aborting propagates into
2508
+ // `transport.sendOne`/`sendBatch` and from there into
2509
+ // `../http/client.ts`'s own retry ladder, which is otherwise the one
2510
+ // thing nothing here could ever cut short.
2511
+ cancelKick() {
2512
+ if (kickTimer !== void 0) {
2513
+ clearTimeout(kickTimer);
2514
+ kickTimer = void 0;
2515
+ }
2516
+ ownSignal.abort();
2416
2517
  },
2417
2518
  bindOpportunisticTriggers() {
2418
2519
  const target = typeof globalThis.addEventListener === "function" ? globalThis : void 0;
@@ -2421,7 +2522,7 @@ function createDrainer(options) {
2421
2522
  };
2422
2523
  }
2423
2524
  const onOnline = () => {
2424
- drainer.kick();
2525
+ drainer.kick({ connectivityRestored: true });
2425
2526
  };
2426
2527
  const onVisible = () => {
2427
2528
  const state = globalThis.document?.visibilityState;
@@ -3097,15 +3198,16 @@ function createOfflineEngine(options) {
3097
3198
  drainer.kick();
3098
3199
  return op;
3099
3200
  },
3100
- async drain() {
3201
+ async drain(drainOptions = {}) {
3101
3202
  await share?.parkOpsPastGrace();
3102
- const report = await drainer.drain();
3203
+ const report = await drainer.drain(drainOptions);
3103
3204
  await blobs?.drain();
3104
3205
  return report;
3105
3206
  },
3106
3207
  close() {
3107
3208
  unbind?.();
3108
3209
  unbind = void 0;
3210
+ drainer.cancelKick();
3109
3211
  events.clear();
3110
3212
  }
3111
3213
  };
@@ -5183,6 +5285,7 @@ exports.MAX_BATCH_OPS = MAX_BATCH_OPS;
5183
5285
  exports.ManagerRole = ManagerRole;
5184
5286
  exports.ManifestMode = ManifestMode;
5185
5287
  exports.OutboxClass = OutboxClass;
5288
+ exports.OutboxRetryCause = OutboxRetryCause;
5186
5289
  exports.OutboxStatus = OutboxStatus;
5187
5290
  exports.PartyKind = PartyKind;
5188
5291
  exports.PickupKind = PickupKind;