kaafil-js 0.1.0-beta.2 → 0.1.0-beta.3

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.
@@ -16,20 +16,96 @@ var SECURITY_SCHEME_CARRIERS = {
16
16
  shareAuth: { kind: "bearer" }
17
17
  };
18
18
  var OperationId = {
19
+ AddChecklistItem: "addChecklistItem",
20
+ AddItineraryItem: "addItineraryItem",
21
+ AdjustFloat: "adjustFloat",
22
+ AssignPickupTraveller: "assignPickupTraveller",
23
+ AssignRoomingBed: "assignRoomingBed",
24
+ AssignSeating: "assignSeating",
25
+ AutoAssignRooming: "autoAssignRooming",
26
+ AutoAssignSeating: "autoAssignSeating",
27
+ BoardPickupTraveller: "boardPickupTraveller",
28
+ ClaimStatusIngest: "claimStatusIngest",
29
+ ClosePickupStop: "closePickupStop",
30
+ ConfirmFileUpload: "confirmFileUpload",
31
+ CreatePickupStop: "createPickupStop",
32
+ CreateRoomingRoom: "createRoomingRoom",
33
+ CreateRoomingStayWindow: "createRoomingStayWindow",
34
+ CreateSeatingVehicle: "createSeatingVehicle",
35
+ CreateTrekWalkIn: "createTrekWalkIn",
36
+ DeleteChecklistItem: "deleteChecklistItem",
37
+ DeleteItineraryItem: "deleteItineraryItem",
38
+ DeletePickupStop: "deletePickupStop",
39
+ DeleteRoomingRoom: "deleteRoomingRoom",
40
+ DeleteRoomingStayWindow: "deleteRoomingStayWindow",
41
+ DeleteSeatingVehicle: "deleteSeatingVehicle",
42
+ ExportCloseoutPack: "exportCloseoutPack",
19
43
  GetShareManifest: "getShareManifest",
20
44
  GetShareSnapshot: "getShareSnapshot",
45
+ IssueFloat: "issueFloat",
46
+ LinkExpenseReceipt: "linkExpenseReceipt",
47
+ LinkSeatingManager: "linkSeatingManager",
48
+ ListChecklistTemplates: "listChecklistTemplates",
49
+ ListCollections: "listCollections",
50
+ ListEligibleCollections: "listEligibleCollections",
51
+ ListExpenses: "listExpenses",
21
52
  ListJourneyTriggers: "listJourneyTriggers",
22
53
  ListManagerNotifications: "listManagerNotifications",
54
+ ListPickupStops: "listPickupStops",
55
+ ListRoomingStayWindows: "listRoomingStayWindows",
23
56
  ListTripVendors: "listTripVendors",
57
+ LockCloseout: "lockCloseout",
58
+ LogExpense: "logExpense",
59
+ PatchChecklistItem: "patchChecklistItem",
60
+ PatchItineraryDay: "patchItineraryDay",
61
+ PatchItineraryItem: "patchItineraryItem",
24
62
  PatchJourneyTrigger: "patchJourneyTrigger",
63
+ PatchPickupStop: "patchPickupStop",
64
+ PatchRoomingRoom: "patchRoomingRoom",
65
+ PatchRoomingStayWindow: "patchRoomingStayWindow",
66
+ PatchSeatingVehicle: "patchSeatingVehicle",
67
+ PostponeTrek: "postponeTrek",
68
+ PullChecklistTemplate: "pullChecklistTemplate",
69
+ ReadChecklistAggregate: "readChecklistAggregate",
70
+ ReadCloseout: "readCloseout",
71
+ ReadExpense: "readExpense",
72
+ ReadFile: "readFile",
73
+ ReadFileUrl: "readFileUrl",
74
+ ReadFloatLedger: "readFloatLedger",
75
+ ReadFloatSummary: "readFloatSummary",
76
+ ReadItinerary: "readItinerary",
77
+ ReadItineraryChangeLog: "readItineraryChangeLog",
25
78
  ReadJourney: "readJourney",
26
79
  ReadJourneyCapabilities: "readJourneyCapabilities",
80
+ ReadManifestByPickup: "readManifestByPickup",
81
+ ReadRoomingBoard: "readRoomingBoard",
82
+ ReadSeatingBoard: "readSeatingBoard",
83
+ ReadTrekBoard: "readTrekBoard",
84
+ ReadTrekWalkInMeta: "readTrekWalkInMeta",
27
85
  RebuildJourney: "rebuildJourney",
86
+ RecordCollection: "recordCollection",
87
+ ReopenPickupStop: "reopenPickupStop",
88
+ ReorderItineraryItem: "reorderItineraryItem",
89
+ ReorderPickupStops: "reorderPickupStops",
90
+ RequestFileUpload: "requestFileUpload",
91
+ ReturnFloat: "returnFloat",
28
92
  RunJourneyStep: "runJourneyStep",
93
+ SaveCloseoutHandover: "saveCloseoutHandover",
29
94
  ShareListForms: "shareListForms",
30
95
  ShareRenderForm: "shareRenderForm",
31
96
  ShareSaveForm: "shareSaveForm",
32
- ShareSubmitForm: "shareSubmitForm"};
97
+ ShareSubmitForm: "shareSubmitForm",
98
+ SubmitExpenseClaim: "submitExpenseClaim",
99
+ SyncPullTrip: "syncPullTrip",
100
+ SyncPush: "syncPush",
101
+ SyncPushShare: "syncPushShare",
102
+ ToggleChecklistItem: "toggleChecklistItem",
103
+ UnlinkSeatingManager: "unlinkSeatingManager",
104
+ UnlockCloseout: "unlockCloseout",
105
+ VoidCollection: "voidCollection",
106
+ VoidExpense: "voidExpense",
107
+ WithdrawExpenseClaim: "withdrawExpenseClaim"
108
+ };
33
109
  var OPERATION_SECURITY = {
34
110
  acceptConsoleInvite: [],
35
111
  acceptPlatformAdminInvite: [],
@@ -82,6 +158,7 @@ var OPERATION_SECURITY = {
82
158
  deleteSeatingVehicle: ["managerAuth"],
83
159
  dispatchForm: ["managerAuth", "apiKeyAuth"],
84
160
  editWebhookEndpoint: ["consoleAuth"],
161
+ exportCloseoutPack: ["managerAuth", "apiKeyAuth"],
85
162
  exportFormResponses: ["apiKeyAuth", "managerAuth"],
86
163
  getForm: ["apiKeyAuth", "agencyAdminAuth", "managerAuth"],
87
164
  getFormAggregate: ["apiKeyAuth"],
@@ -126,6 +203,7 @@ var OPERATION_SECURITY = {
126
203
  listTripVendors: ["apiKeyAuth", "managerAuth", "agencyAdminAuth"],
127
204
  listWebhookDeliveries: ["apiKeyAuth"],
128
205
  listWebhookEndpoints: ["consoleAuth"],
206
+ lockCloseout: ["managerAuth"],
129
207
  logExpense: ["managerAuth"],
130
208
  managerCreateFormResponse: ["managerAuth"],
131
209
  markNotificationRead: ["managerAuth"],
@@ -165,6 +243,7 @@ var OPERATION_SECURITY = {
165
243
  readAgencyFeedbackSummary: ["agencyAdminAuth", "apiKeyAuth"],
166
244
  readApiKey: ["consoleAuth"],
167
245
  readChecklistAggregate: ["managerAuth", "apiKeyAuth"],
246
+ readCloseout: ["managerAuth", "apiKeyAuth"],
168
247
  readCommsConfig: ["apiKeyAuth"],
169
248
  readConsoleAudit: ["consoleAuth"],
170
249
  readConsoleChecklist: ["consoleAuth"],
@@ -227,6 +306,7 @@ var OPERATION_SECURITY = {
227
306
  rotateApiKey: ["consoleAuth"],
228
307
  rotateWebhookEndpointSecret: ["consoleAuth"],
229
308
  runJourneyStep: ["apiKeyAuth"],
309
+ saveCloseoutHandover: ["managerAuth"],
230
310
  sendMessage: ["apiKeyAuth"],
231
311
  setPlatformPartnerStatus: ["platformAdminAuth"],
232
312
  shareListForms: ["shareAuth"],
@@ -234,10 +314,15 @@ var OPERATION_SECURITY = {
234
314
  shareSaveForm: ["shareAuth"],
235
315
  shareSubmitForm: ["shareAuth"],
236
316
  submitExpenseClaim: ["managerAuth"],
317
+ syncDigest: ["apiKeyAuth"],
318
+ syncPullTrip: ["managerAuth", "apiKeyAuth"],
319
+ syncPush: ["managerAuth", "apiKeyAuth"],
320
+ syncPushShare: [],
237
321
  toggleChecklistItem: ["managerAuth"],
238
322
  unarchiveForm: ["apiKeyAuth", "agencyAdminAuth"],
239
323
  unassignManager: ["apiKeyAuth"],
240
324
  unlinkSeatingManager: ["managerAuth"],
325
+ unlockCloseout: ["apiKeyAuth"],
241
326
  upsertAgencyAdmin: ["apiKeyAuth"],
242
327
  upsertManager: ["apiKeyAuth"],
243
328
  upsertTravellerProfile: ["apiKeyAuth"],
@@ -298,6 +383,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
298
383
  deleteSeatingVehicle: false,
299
384
  dispatchForm: true,
300
385
  editWebhookEndpoint: true,
386
+ exportCloseoutPack: false,
301
387
  exportFormResponses: false,
302
388
  getForm: false,
303
389
  getFormAggregate: false,
@@ -342,6 +428,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
342
428
  listTripVendors: false,
343
429
  listWebhookDeliveries: false,
344
430
  listWebhookEndpoints: false,
431
+ lockCloseout: true,
345
432
  logExpense: true,
346
433
  managerCreateFormResponse: true,
347
434
  markNotificationRead: true,
@@ -381,6 +468,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
381
468
  readAgencyFeedbackSummary: false,
382
469
  readApiKey: false,
383
470
  readChecklistAggregate: false,
471
+ readCloseout: false,
384
472
  readCommsConfig: false,
385
473
  readConsoleAudit: false,
386
474
  readConsoleChecklist: false,
@@ -443,6 +531,7 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
443
531
  rotateApiKey: true,
444
532
  rotateWebhookEndpointSecret: true,
445
533
  runJourneyStep: true,
534
+ saveCloseoutHandover: true,
446
535
  sendMessage: true,
447
536
  setPlatformPartnerStatus: false,
448
537
  shareListForms: false,
@@ -450,10 +539,15 @@ var OPERATION_ACCEPTS_IDEMPOTENCY_KEY = {
450
539
  shareSaveForm: true,
451
540
  shareSubmitForm: true,
452
541
  submitExpenseClaim: true,
542
+ syncDigest: false,
543
+ syncPullTrip: false,
544
+ syncPush: false,
545
+ syncPushShare: false,
453
546
  toggleChecklistItem: true,
454
547
  unarchiveForm: false,
455
548
  unassignManager: true,
456
549
  unlinkSeatingManager: false,
550
+ unlockCloseout: true,
457
551
  upsertAgencyAdmin: true,
458
552
  upsertManager: true,
459
553
  upsertTravellerProfile: true,
@@ -495,10 +589,12 @@ var KaafilErrorCode = {
495
589
  SecretNotReplayable: "SECRET_NOT_REPLAYABLE",
496
590
  ShareTokenExpired: "SHARE_TOKEN_EXPIRED",
497
591
  ShareTokenRevoked: "SHARE_TOKEN_REVOKED",
592
+ ShareWriteGraceExpired: "SHARE_WRITE_GRACE_EXPIRED",
498
593
  StayWindowHasAssignments: "STAY_WINDOW_HAS_ASSIGNMENTS",
499
594
  StayWindowOverlap: "STAY_WINDOW_OVERLAP",
500
595
  StopHasPending: "STOP_HAS_PENDING",
501
596
  SubjectRequired: "SUBJECT_REQUIRED",
597
+ SyncTargetRefused: "SYNC_TARGET_REFUSED",
502
598
  TenantScopeMissing: "TENANT_SCOPE_MISSING",
503
599
  Unauthenticated: "UNAUTHENTICATED",
504
600
  UploadMismatch: "UPLOAD_MISMATCH",
@@ -546,10 +642,12 @@ var ERROR_CODE_TABLE = {
546
642
  SECRET_NOT_REPLAYABLE: { status: 409, retryability: "no", outboxClass: "CONFLICT" },
547
643
  SHARE_TOKEN_EXPIRED: { status: 401, retryability: "no", outboxClass: "FATAL" },
548
644
  SHARE_TOKEN_REVOKED: { status: 401, retryability: "no", outboxClass: "FATAL" },
645
+ SHARE_WRITE_GRACE_EXPIRED: { status: 422, retryability: "no", outboxClass: "FATAL" },
549
646
  STAY_WINDOW_HAS_ASSIGNMENTS: { status: 422, retryability: "no", outboxClass: "FATAL" },
550
647
  STAY_WINDOW_OVERLAP: { status: 422, retryability: "no", outboxClass: "FATAL" },
551
648
  STOP_HAS_PENDING: { status: 422, retryability: "no", outboxClass: "FATAL" },
552
649
  SUBJECT_REQUIRED: { status: 422, retryability: "no", outboxClass: "FATAL" },
650
+ SYNC_TARGET_REFUSED: { status: 422, retryability: "no", outboxClass: "FATAL" },
553
651
  TENANT_SCOPE_MISSING: { status: 500, retryability: "yes", outboxClass: "TRANSIENT" },
554
652
  UNAUTHENTICATED: { status: 401, retryability: "after-refresh", outboxClass: "FATAL" },
555
653
  UPLOAD_MISMATCH: { status: 422, retryability: "no", outboxClass: "FATAL" },
@@ -1184,7 +1282,8 @@ function createHttpClient(config) {
1184
1282
  random: config.random
1185
1283
  };
1186
1284
  return {
1187
- execute: (request) => execute(ctx, request)
1285
+ execute: (request) => execute(ctx, request),
1286
+ executeBinary: (request) => executeBinary(ctx, request)
1188
1287
  };
1189
1288
  }
1190
1289
  function renderPath(template, params) {
@@ -1241,7 +1340,7 @@ async function buildHeaders(ctx, request, idempotencyKey, hasBody) {
1241
1340
  const acceptedSchemes = OPERATION_SECURITY[request.operationId];
1242
1341
  const credential = await ctx.credentials.resolveHeaders(request.operationId, acceptedSchemes);
1243
1342
  const headers = new Headers();
1244
- headers.set("Accept", "application/json");
1343
+ headers.set("Accept", request.accept ?? "application/json");
1245
1344
  if (hasBody) {
1246
1345
  headers.set("Content-Type", "application/json");
1247
1346
  }
@@ -1317,7 +1416,17 @@ function describeCrossOriginSuspect(url) {
1317
1416
  }
1318
1417
  return `Request failed while calling a different origin (${url.origin}) than the page's own origin (${origin}). The most likely cause is that the API has not allowlisted this origin for CORS \u2014 but the browser withholds the actual reason from JavaScript when it blocks a cross-origin response, so the SDK cannot confirm this; a genuine network outage produces the same rejection. If this is unexpected, the fix is server-side: add this origin to the API's CORS allowlist.`;
1319
1418
  }
1320
- async function sendOnce(ctx, request, idempotencyKey) {
1419
+ async function throwFromErrorResponse(response, status, requestId) {
1420
+ const text = await response.text();
1421
+ const body = text.length > 0 ? tryParseJson(text) : void 0;
1422
+ const retryAfterSeconds = parseRetryAfterSeconds(response.headers.get("retry-after"));
1423
+ throw fromEnvelope(body, {
1424
+ status,
1425
+ ...requestId !== void 0 ? { requestId } : {},
1426
+ ...retryAfterSeconds !== void 0 ? { retryAfterSeconds } : {}
1427
+ });
1428
+ }
1429
+ async function sendOnceWith(ctx, request, idempotencyKey, readSuccess) {
1321
1430
  const hasBody = request.body !== void 0;
1322
1431
  const renderedPath = renderPath(request.path, request.pathParams);
1323
1432
  const url = buildUrl(ctx.baseUrl, renderedPath, request.query);
@@ -1332,23 +1441,10 @@ async function sendOnce(ctx, request, idempotencyKey) {
1332
1441
  });
1333
1442
  const requestId = response.headers.get("x-request-id") ?? void 0;
1334
1443
  const status = response.status;
1335
- const text = await response.text();
1336
- const body = text.length > 0 ? tryParseJson(text) : void 0;
1337
1444
  if (response.ok) {
1338
- if (!isSuccessEnvelope(body)) {
1339
- throw new KaafilNetworkError(`Received an unrecognizable success body for HTTP ${status}`, {
1340
- status,
1341
- ...requestId !== void 0 ? { requestId } : {}
1342
- });
1343
- }
1344
- return { data: body.data, meta: buildResponseMeta(status, requestId, body.meta) };
1445
+ return await readSuccess(response, status, requestId);
1345
1446
  }
1346
- const retryAfterSeconds = parseRetryAfterSeconds(response.headers.get("retry-after"));
1347
- throw fromEnvelope(body, {
1348
- status,
1349
- ...requestId !== void 0 ? { requestId } : {},
1350
- ...retryAfterSeconds !== void 0 ? { retryAfterSeconds } : {}
1351
- });
1447
+ return await throwFromErrorResponse(response, status, requestId);
1352
1448
  } catch (error) {
1353
1449
  if (isKaafilError(error)) {
1354
1450
  throw error;
@@ -1366,6 +1462,30 @@ async function sendOnce(ctx, request, idempotencyKey) {
1366
1462
  combined.cleanup();
1367
1463
  }
1368
1464
  }
1465
+ function sendOnce(ctx, request, idempotencyKey) {
1466
+ return sendOnceWith(ctx, request, idempotencyKey, async (response, status, requestId) => {
1467
+ const text = await response.text();
1468
+ const body = text.length > 0 ? tryParseJson(text) : void 0;
1469
+ if (!isSuccessEnvelope(body)) {
1470
+ throw new KaafilNetworkError(`Received an unrecognizable success body for HTTP ${status}`, {
1471
+ status,
1472
+ ...requestId !== void 0 ? { requestId } : {}
1473
+ });
1474
+ }
1475
+ return { data: body.data, meta: buildResponseMeta(status, requestId, body.meta) };
1476
+ });
1477
+ }
1478
+ function sendOnceBinary(ctx, request, idempotencyKey) {
1479
+ return sendOnceWith(ctx, request, idempotencyKey, async (response, status, requestId) => {
1480
+ const buffer = await response.arrayBuffer();
1481
+ const meta = {
1482
+ status,
1483
+ requestId,
1484
+ contentType: response.headers.get("content-type") ?? void 0
1485
+ };
1486
+ return { bytes: new Uint8Array(buffer), meta };
1487
+ });
1488
+ }
1369
1489
  var MANAGER_TOKENS_REFRESH_PATH = "/api/v1/auth/manager-tokens/refresh";
1370
1490
  var AGENCY_ADMIN_TOKENS_REFRESH_PATH = "/api/v1/auth/agency-admin-tokens/refresh";
1371
1491
  function createRotatingSessionRefreshExchange(baseUrl, refreshPath, networkErrorMessage) {
@@ -1433,17 +1553,19 @@ function toFailureOutcome(error) {
1433
1553
  ...error instanceof KaafilRateLimitedError && error.retryAfterSeconds !== void 0 ? { retryAfterSeconds: error.retryAfterSeconds } : {}
1434
1554
  };
1435
1555
  }
1436
- async function execute(ctx, request) {
1556
+ async function runWithLadder(ctx, request, send) {
1437
1557
  const idempotencyKey = OPERATION_ACCEPTS_IDEMPOTENCY_KEY[request.operationId] ? request.idempotencyKey ?? globalThis.crypto.randomUUID() : void 0;
1438
1558
  let lastError;
1439
1559
  let refreshAttempted = false;
1440
1560
  const sendAndClassify = async () => {
1441
1561
  try {
1442
- const { data, meta } = await sendOnce(ctx, request, idempotencyKey);
1443
- return { ok: true, value: attachMeta(data, meta) };
1562
+ return { ok: true, value: await send(idempotencyKey) };
1444
1563
  } catch (error) {
1445
1564
  const typed = toKaafilError(error);
1446
1565
  lastError = typed;
1566
+ if (typed.kind === "transport" && !isRetryable(typed)) {
1567
+ throw typed;
1568
+ }
1447
1569
  return toFailureOutcome(typed);
1448
1570
  }
1449
1571
  };
@@ -1483,167 +1605,2695 @@ async function execute(ctx, request) {
1483
1605
  throw error;
1484
1606
  }
1485
1607
  }
1608
+ function execute(ctx, request) {
1609
+ return runWithLadder(ctx, request, async (idempotencyKey) => {
1610
+ const { data, meta } = await sendOnce(ctx, request, idempotencyKey);
1611
+ return attachMeta(data, meta);
1612
+ });
1613
+ }
1614
+ function executeBinary(ctx, request) {
1615
+ return runWithLadder(
1616
+ ctx,
1617
+ request,
1618
+ (idempotencyKey) => sendOnceBinary(ctx, request, idempotencyKey)
1619
+ );
1620
+ }
1486
1621
 
1487
1622
  // src/idempotency.ts
1488
1623
  function newIdempotencyKey() {
1489
1624
  return globalThis.crypto.randomUUID();
1490
1625
  }
1491
1626
 
1492
- // src/resources/journey.ts
1493
- var DEFAULT_WAIT_UNTIL_READY_TIMEOUT_MS = 6e4;
1494
- var DEFAULT_WAIT_UNTIL_READY_POLL_INTERVAL_MS = 1e3;
1495
- function createJourneyResource(client) {
1496
- const resource = {
1497
- async get(options) {
1498
- const { tripRef, signal } = options;
1627
+ // src/resources/sync.ts
1628
+ var KaafilShareBatchUnauthenticatedError = class _KaafilShareBatchUnauthenticatedError extends KaafilInvalidRequestError {
1629
+ constructor() {
1630
+ super(
1631
+ `The vendored spec declares no security scheme for "syncPushShare", so a batched share push would be sent with no credential at all, carrying a traveller's queued writes. Refused locally. Drain share ops through their own endpoints (shareSaveForm / shareSubmitForm) until the engine declares shareAuth on POST /api/v1/sync/push/share.`
1632
+ );
1633
+ this.name = "KaafilShareBatchUnauthenticatedError";
1634
+ Object.setPrototypeOf(this, _KaafilShareBatchUnauthenticatedError.prototype);
1635
+ }
1636
+ };
1637
+ function isShareBatchPushAvailable() {
1638
+ return OPERATION_SECURITY[OperationId.SyncPushShare].includes(
1639
+ SecuritySchemeId.ShareAuth
1640
+ );
1641
+ }
1642
+ function createSyncResource(client) {
1643
+ return {
1644
+ async push(options) {
1645
+ const { ops, signal } = options;
1646
+ const body = { ops: [...ops] };
1499
1647
  return client.execute({
1500
- method: "GET",
1501
- operationId: OperationId.ReadJourney,
1502
- path: "/api/v1/trips/{ref}/journey",
1503
- pathParams: { ref: tripRef },
1648
+ method: "POST",
1649
+ operationId: OperationId.SyncPush,
1650
+ path: "/api/v1/sync/push",
1651
+ body,
1504
1652
  ...signal !== void 0 ? { signal } : {}
1505
1653
  });
1506
1654
  },
1507
- async capabilities(options) {
1508
- const { tripRef, signal } = options;
1655
+ async pullTrip(options) {
1656
+ const { tripRef, since, signal } = options;
1509
1657
  return client.execute({
1510
1658
  method: "GET",
1511
- operationId: OperationId.ReadJourneyCapabilities,
1512
- path: "/api/v1/trips/{ref}/journey/capabilities",
1659
+ operationId: OperationId.SyncPullTrip,
1660
+ path: "/api/v1/trips/{ref}/sync",
1513
1661
  pathParams: { ref: tripRef },
1662
+ // A `since` of `undefined` is omitted by `RequestDescriptor`'s own
1663
+ // rule, which is exactly the cold-start shape: no `?since=` at all.
1664
+ query: { since },
1514
1665
  ...signal !== void 0 ? { signal } : {}
1515
1666
  });
1516
1667
  },
1517
- async rebuild(options) {
1518
- const { tripRef, idempotencyKey, signal } = options;
1668
+ async pushShare(options) {
1669
+ if (!isShareBatchPushAvailable()) {
1670
+ throw new KaafilShareBatchUnauthenticatedError();
1671
+ }
1672
+ const { ops, signal } = options;
1673
+ const body = { ops: [...ops] };
1519
1674
  return client.execute({
1520
1675
  method: "POST",
1521
- operationId: OperationId.RebuildJourney,
1522
- path: "/api/v1/trips/{ref}/journey/rebuild",
1523
- pathParams: { ref: tripRef },
1524
- ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
1676
+ operationId: OperationId.SyncPushShare,
1677
+ path: "/api/v1/sync/push/share",
1678
+ body,
1525
1679
  ...signal !== void 0 ? { signal } : {}
1526
1680
  });
1681
+ }
1682
+ };
1683
+ }
1684
+
1685
+ // src/http/classify.ts
1686
+ var OUTBOX_CLASS_TO_VERDICT = {
1687
+ TRANSIENT: "transient",
1688
+ CONFLICT: "conflict",
1689
+ FATAL: "fatal"
1690
+ };
1691
+ function classifyFailure(input) {
1692
+ if (input.status === null) {
1693
+ return "transient";
1694
+ }
1695
+ const entry = input.code !== void 0 ? ERROR_CODE_TABLE[input.code] : void 0;
1696
+ if (entry !== void 0) {
1697
+ return OUTBOX_CLASS_TO_VERDICT[entry.outboxClass];
1698
+ }
1699
+ if (input.status === 429 || input.status >= 500 && input.status <= 599 && input.status !== 501) {
1700
+ return "transient";
1701
+ }
1702
+ if (input.status === 409) {
1703
+ return "conflict";
1704
+ }
1705
+ return "fatal";
1706
+ }
1707
+
1708
+ // src/offline/blob.ts
1709
+ var BlobStatus = {
1710
+ Pending: "pending",
1711
+ Confirmed: "confirmed",
1712
+ Parked: "parked"
1713
+ };
1714
+ function createBlobLane(options) {
1715
+ const key = `${options.keyPrefix}:blobs`;
1716
+ const now = options.now ?? Date.now;
1717
+ const random = options.random ?? Math.random;
1718
+ let blobs = /* @__PURE__ */ new Map();
1719
+ const bodyBuilders = /* @__PURE__ */ new Map();
1720
+ let backfills = /* @__PURE__ */ new Map();
1721
+ async function persist() {
1722
+ const shape = {
1723
+ blobs: [...blobs.values()],
1724
+ backfills: Object.fromEntries(backfills)
1725
+ };
1726
+ await options.storage.set(key, JSON.stringify(shape));
1727
+ }
1728
+ async function update(id, patch) {
1729
+ const held = blobs.get(id);
1730
+ if (held === void 0) {
1731
+ return void 0;
1732
+ }
1733
+ const next = { ...held, ...patch };
1734
+ blobs.set(id, next);
1735
+ await persist();
1736
+ return next;
1737
+ }
1738
+ async function park(id, reason) {
1739
+ const record = await update(id, {
1740
+ status: BlobStatus.Parked,
1741
+ parkReason: reason,
1742
+ nextRetryAt: null
1743
+ });
1744
+ if (record !== void 0) {
1745
+ options.onParked?.(record);
1746
+ }
1747
+ }
1748
+ async function retryLater(record) {
1749
+ await update(record.id, {
1750
+ attemptCount: record.attemptCount + 1,
1751
+ nextRetryAt: now() + computeRetryDelayMs(record.attemptCount + 1, { random })
1752
+ });
1753
+ }
1754
+ async function driveOne(record) {
1755
+ const backfill = backfills.get(record.id);
1756
+ const buildBody = bodyBuilders.get(record.id);
1757
+ if (backfill === void 0 || buildBody === void 0) {
1758
+ await park(
1759
+ record.id,
1760
+ "No back-fill builder is registered for this blob in the current process, so the file key could not be written onto the parent entity. Re-register it and re-enqueue."
1761
+ );
1762
+ return "parked";
1763
+ }
1764
+ const bytes = await options.source(record.id);
1765
+ if (bytes === void 0) {
1766
+ await park(
1767
+ record.id,
1768
+ "The bytes for this attachment were not retained across the restart, so it can never be uploaded. The entity it belongs to is unaffected."
1769
+ );
1770
+ return "parked";
1771
+ }
1772
+ let fileId = record.fileId;
1773
+ if (fileId === void 0) {
1774
+ try {
1775
+ const created = await options.uploader.request({
1776
+ contentType: record.contentType,
1777
+ sizeBytes: record.sizeBytes,
1778
+ tripRef: record.tripRef
1779
+ });
1780
+ fileId = created.fileId;
1781
+ await update(record.id, { fileId });
1782
+ const put = await options.uploader.put({
1783
+ uploadUrl: created.uploadUrl,
1784
+ bytes,
1785
+ contentType: record.contentType
1786
+ });
1787
+ if (put.status < 200 || put.status >= 300) {
1788
+ await retryLater({ ...record, fileId });
1789
+ return "pending";
1790
+ }
1791
+ } catch {
1792
+ await retryLater(record);
1793
+ return "pending";
1794
+ }
1795
+ }
1796
+ let confirmStatus;
1797
+ let confirmCode;
1798
+ try {
1799
+ const confirmed = await options.uploader.confirm({ fileId });
1800
+ confirmStatus = confirmed.status;
1801
+ confirmCode = confirmed.code;
1802
+ } catch {
1803
+ await retryLater(record);
1804
+ return "pending";
1805
+ }
1806
+ if (confirmStatus < 200 || confirmStatus >= 300) {
1807
+ const verdict = classifyFailure({
1808
+ status: confirmStatus,
1809
+ ...confirmCode !== void 0 ? { code: confirmCode } : {}
1810
+ });
1811
+ if (verdict === "transient") {
1812
+ await retryLater(record);
1813
+ return "pending";
1814
+ }
1815
+ await park(
1816
+ record.id,
1817
+ `The upload could not be confirmed (${confirmCode ?? confirmStatus}). The entity it belongs to is unaffected.`
1818
+ );
1819
+ return "parked";
1820
+ }
1821
+ await options.outbox.enqueue({
1822
+ tripRef: record.tripRef,
1823
+ method: backfill.method,
1824
+ path: backfill.path,
1825
+ operationId: backfill.operationId,
1826
+ body: buildBody(fileId),
1827
+ ...backfill.entity !== void 0 ? { entity: backfill.entity } : {},
1828
+ ...backfill.ifMatch !== void 0 ? { ifMatch: backfill.ifMatch } : {}
1829
+ });
1830
+ await update(record.id, { status: BlobStatus.Confirmed, nextRetryAt: null });
1831
+ return "confirmed";
1832
+ }
1833
+ return {
1834
+ async load() {
1835
+ blobs = /* @__PURE__ */ new Map();
1836
+ backfills = /* @__PURE__ */ new Map();
1837
+ const raw = await options.storage.get(key);
1838
+ if (raw === void 0) {
1839
+ return;
1840
+ }
1841
+ let parsed;
1842
+ try {
1843
+ parsed = JSON.parse(raw);
1844
+ } catch {
1845
+ return;
1846
+ }
1847
+ for (const record of parsed.blobs ?? []) {
1848
+ blobs.set(record.id, record);
1849
+ }
1850
+ for (const [id, shape] of Object.entries(parsed.backfills ?? {})) {
1851
+ backfills.set(id, shape);
1852
+ }
1527
1853
  },
1528
- async runStep(options) {
1529
- const { tripRef, stepId, idempotencyKey, signal } = options;
1530
- return client.execute({
1531
- method: "POST",
1532
- operationId: OperationId.RunJourneyStep,
1533
- path: "/api/v1/trips/{ref}/journey/steps/{stepId}/run",
1534
- pathParams: { ref: tripRef, stepId },
1535
- ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
1536
- ...signal !== void 0 ? { signal } : {}
1854
+ async enqueue(args) {
1855
+ const record = {
1856
+ id: args.blobId,
1857
+ tripRef: args.tripRef,
1858
+ parentOpId: args.parentOpId,
1859
+ contentType: args.contentType,
1860
+ sizeBytes: args.sizeBytes,
1861
+ status: BlobStatus.Pending,
1862
+ attemptCount: 0,
1863
+ nextRetryAt: null,
1864
+ fileId: void 0,
1865
+ parkReason: void 0
1866
+ };
1867
+ blobs.set(record.id, record);
1868
+ backfills.set(record.id, {
1869
+ method: args.backfill.method,
1870
+ path: args.backfill.path,
1871
+ operationId: args.backfill.operationId,
1872
+ entity: args.backfill.entity,
1873
+ ifMatch: args.backfill.ifMatch
1537
1874
  });
1875
+ bodyBuilders.set(record.id, args.backfill.body);
1876
+ await persist();
1877
+ return record;
1538
1878
  },
1539
- async waitUntilReady(options) {
1540
- const {
1541
- tripRef,
1542
- timeoutMs = DEFAULT_WAIT_UNTIL_READY_TIMEOUT_MS,
1543
- pollIntervalMs = DEFAULT_WAIT_UNTIL_READY_POLL_INTERVAL_MS,
1544
- signal
1545
- } = options;
1546
- const deadlineAt = Date.now() + timeoutMs;
1547
- for (; ; ) {
1548
- try {
1549
- return await resource.get({ tripRef, ...signal !== void 0 ? { signal } : {} });
1550
- } catch (error) {
1551
- if (!(error instanceof KaafilNotFoundError)) {
1552
- throw error;
1553
- }
1554
- const remainingMs = deadlineAt - Date.now();
1555
- if (remainingMs <= 0) {
1556
- throw new KaafilTimeoutError(
1557
- `journey.waitUntilReady timed out after ${String(timeoutMs)}ms waiting for trip "${tripRef}" to become ready. The most likely cause is that the background worker that consumes the build queue is not running against this engine.`,
1558
- { cause: error }
1559
- );
1560
- }
1561
- try {
1562
- await delayWithAbort(Math.min(pollIntervalMs, remainingMs), signal);
1563
- } catch (sleepError) {
1564
- throw new KaafilAbortError("Request aborted", { cause: sleepError });
1565
- }
1879
+ async drain() {
1880
+ let confirmed = 0;
1881
+ let parked = 0;
1882
+ const at = now();
1883
+ for (const record of [...blobs.values()]) {
1884
+ if (record.status !== BlobStatus.Pending) {
1885
+ continue;
1886
+ }
1887
+ if (record.nextRetryAt !== null && record.nextRetryAt > at) {
1888
+ continue;
1889
+ }
1890
+ const outcome = await driveOne(record);
1891
+ if (outcome === "confirmed") {
1892
+ confirmed += 1;
1893
+ } else if (outcome === "parked") {
1894
+ parked += 1;
1566
1895
  }
1567
1896
  }
1568
- },
1569
- triggers: {
1570
- async list(options) {
1571
- const { agencyRef, signal } = options;
1572
- return client.execute({
1573
- method: "GET",
1574
- operationId: OperationId.ListJourneyTriggers,
1575
- path: "/api/v1/agencies/{ref}/journey-triggers",
1576
- pathParams: { ref: agencyRef },
1577
- ...signal !== void 0 ? { signal } : {}
1578
- });
1579
- },
1580
- async patch(options) {
1581
- const { agencyRef, key, version, idempotencyKey, signal, ...body } = options;
1582
- return client.execute({
1583
- method: "PATCH",
1584
- operationId: OperationId.PatchJourneyTrigger,
1585
- path: "/api/v1/agencies/{ref}/journey-triggers/{key}",
1586
- pathParams: { ref: agencyRef, key },
1587
- body,
1588
- headers: { "If-Match": String(version) },
1589
- ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
1590
- ...signal !== void 0 ? { signal } : {}
1591
- });
1897
+ let pending = 0;
1898
+ for (const record of blobs.values()) {
1899
+ if (record.status === BlobStatus.Pending) {
1900
+ pending += 1;
1901
+ }
1592
1902
  }
1903
+ return { confirmed, parked, pending };
1904
+ },
1905
+ all() {
1906
+ return [...blobs.values()];
1593
1907
  }
1594
1908
  };
1595
- return resource;
1596
1909
  }
1597
1910
 
1598
- // src/resources/notifications.ts
1599
- function createNotificationsResource(client) {
1911
+ // src/offline/outbox.ts
1912
+ var OutboxStatus = {
1913
+ /** Waiting to be sent, or waiting out a backoff rung. */
1914
+ Pending: "pending",
1915
+ /** Handed to the transport; not yet answered. */
1916
+ Inflight: "inflight",
1917
+ /** Terminal failure. Out of the FIFO ordering; surfaced to the user. */
1918
+ Parked: "parked",
1919
+ /** Terminal success. Pruned on the next persist. */
1920
+ Done: "done"
1921
+ };
1922
+ function createOutbox(options) {
1923
+ const key = `${options.keyPrefix}:outbox`;
1924
+ const mintId = options.newId ?? newIdempotencyKey;
1925
+ let ops = /* @__PURE__ */ new Map();
1926
+ let seq = 0;
1927
+ function ordered() {
1928
+ return [...ops.values()].sort((a, b) => a.seq - b.seq);
1929
+ }
1930
+ async function persist() {
1931
+ for (const [id, op] of [...ops]) {
1932
+ if (op.status === OutboxStatus.Done) {
1933
+ ops.delete(id);
1934
+ }
1935
+ }
1936
+ const shape = { seq, ops: ordered() };
1937
+ await options.storage.set(key, JSON.stringify(shape));
1938
+ }
1939
+ async function mutate(opId, patch) {
1940
+ const op = ops.get(opId);
1941
+ if (op === void 0) {
1942
+ return;
1943
+ }
1944
+ ops.set(opId, { ...op, ...patch });
1945
+ await persist();
1946
+ }
1600
1947
  return {
1601
- async list(options = {}) {
1602
- const { since, signal } = options;
1603
- return client.execute({
1604
- method: "GET",
1605
- operationId: OperationId.ListManagerNotifications,
1606
- path: "/api/v1/managers/me/notifications",
1607
- ...since !== void 0 ? { query: { since } } : {},
1608
- ...signal !== void 0 ? { signal } : {}
1948
+ async load() {
1949
+ ops = /* @__PURE__ */ new Map();
1950
+ seq = 0;
1951
+ const raw = await options.storage.get(key);
1952
+ if (raw === void 0) {
1953
+ return;
1954
+ }
1955
+ let parsed;
1956
+ try {
1957
+ parsed = JSON.parse(raw);
1958
+ } catch {
1959
+ return;
1960
+ }
1961
+ seq = typeof parsed.seq === "number" ? parsed.seq : 0;
1962
+ for (const op of parsed.ops ?? []) {
1963
+ ops.set(op.id, {
1964
+ ...op,
1965
+ status: op.status === OutboxStatus.Inflight ? OutboxStatus.Pending : op.status
1966
+ });
1967
+ }
1968
+ },
1969
+ async enqueue(input) {
1970
+ seq += 1;
1971
+ const op = {
1972
+ id: mintId(),
1973
+ seq,
1974
+ tripRef: input.tripRef,
1975
+ method: input.method,
1976
+ path: input.path,
1977
+ operationId: input.operationId,
1978
+ body: input.body,
1979
+ ifMatch: input.ifMatch,
1980
+ entity: input.entity,
1981
+ idempotencyKey: input.idempotencyKey ?? newIdempotencyKey(),
1982
+ enqueuedAt: input.enqueuedAt,
1983
+ receiptPending: input.receiptPending === true,
1984
+ blobId: input.blobId,
1985
+ status: OutboxStatus.Pending,
1986
+ attemptCount: 0,
1987
+ nextRetryAt: null,
1988
+ refreshAttempted: false,
1989
+ parkReason: void 0
1990
+ };
1991
+ ops.set(op.id, op);
1992
+ await persist();
1993
+ return op;
1994
+ },
1995
+ get(opId) {
1996
+ return ops.get(opId);
1997
+ },
1998
+ all() {
1999
+ return ordered();
2000
+ },
2001
+ lanes() {
2002
+ const seen = /* @__PURE__ */ new Set();
2003
+ for (const op of ops.values()) {
2004
+ if (op.status === OutboxStatus.Pending) {
2005
+ seen.add(op.tripRef);
2006
+ }
2007
+ }
2008
+ return [...seen];
2009
+ },
2010
+ head(tripRef) {
2011
+ return ordered().find((op) => op.tripRef === tripRef && op.status === OutboxStatus.Pending);
2012
+ },
2013
+ readyPrefix(tripRef, at, limit) {
2014
+ const out = [];
2015
+ for (const op of ordered()) {
2016
+ if (op.tripRef !== tripRef || op.status !== OutboxStatus.Pending) {
2017
+ continue;
2018
+ }
2019
+ if (op.nextRetryAt !== null && op.nextRetryAt > at) {
2020
+ break;
2021
+ }
2022
+ out.push(op);
2023
+ if (out.length >= limit) {
2024
+ break;
2025
+ }
2026
+ }
2027
+ return out;
2028
+ },
2029
+ async markInflight(opId) {
2030
+ await mutate(opId, { status: OutboxStatus.Inflight });
2031
+ },
2032
+ async markDone(opId) {
2033
+ await mutate(opId, { status: OutboxStatus.Done });
2034
+ },
2035
+ async park(opId, reason) {
2036
+ const op = ops.get(opId);
2037
+ await mutate(opId, {
2038
+ status: OutboxStatus.Parked,
2039
+ parkReason: reason,
2040
+ attemptCount: (op?.attemptCount ?? 0) + 1,
2041
+ nextRetryAt: null
2042
+ });
2043
+ },
2044
+ async scheduleRetry(opId, nextRetryAt) {
2045
+ const op = ops.get(opId);
2046
+ await mutate(opId, {
2047
+ status: OutboxStatus.Pending,
2048
+ attemptCount: (op?.attemptCount ?? 0) + 1,
2049
+ nextRetryAt
2050
+ });
2051
+ },
2052
+ async requeue(opId) {
2053
+ await mutate(opId, { status: OutboxStatus.Pending });
2054
+ },
2055
+ async markRefreshAttempted(opId) {
2056
+ await mutate(opId, { refreshAttempted: true });
2057
+ },
2058
+ async reissue(opId, patch) {
2059
+ const op = ops.get(opId);
2060
+ if (op === void 0) {
2061
+ return;
2062
+ }
2063
+ ops.set(opId, {
2064
+ ...op,
2065
+ status: OutboxStatus.Pending,
2066
+ nextRetryAt: null,
2067
+ attemptCount: op.attemptCount + 1,
2068
+ ...patch.body !== void 0 ? { body: patch.body } : {},
2069
+ ...patch.ifMatch !== void 0 ? { ifMatch: patch.ifMatch } : {}
1609
2070
  });
2071
+ await persist();
2072
+ },
2073
+ async drop(opId) {
2074
+ if (!ops.delete(opId)) {
2075
+ return;
2076
+ }
2077
+ await persist();
2078
+ },
2079
+ counts() {
2080
+ let pending = 0;
2081
+ let inflight = 0;
2082
+ let parked = 0;
2083
+ for (const op of ops.values()) {
2084
+ if (op.status === OutboxStatus.Pending) {
2085
+ pending += 1;
2086
+ } else if (op.status === OutboxStatus.Inflight) {
2087
+ inflight += 1;
2088
+ } else if (op.status === OutboxStatus.Parked) {
2089
+ parked += 1;
2090
+ }
2091
+ }
2092
+ return { pending, inflight, parked };
1610
2093
  }
1611
2094
  };
1612
2095
  }
1613
2096
 
1614
- // src/resources/share.ts
1615
- function createShareResource(client) {
1616
- return {
1617
- async snapshot(options) {
1618
- const { token, signal } = options;
1619
- return client.execute({
1620
- method: "GET",
1621
- operationId: OperationId.GetShareSnapshot,
1622
- path: "/api/v1/share/{token}",
1623
- pathParams: { token },
1624
- ...signal !== void 0 ? { signal } : {}
2097
+ // src/offline/reconcile.ts
2098
+ function readCurrentVersion(details) {
2099
+ const value = details?.currentVersion;
2100
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2101
+ }
2102
+ async function reconcileConflict(args) {
2103
+ const { op, transport, snapshot, resolver } = args;
2104
+ const currentVersion = readCurrentVersion(args.details);
2105
+ let current;
2106
+ if (op.entity !== void 0 && transport.readEntity !== void 0) {
2107
+ let read;
2108
+ try {
2109
+ read = await transport.readEntity({
2110
+ tripRef: op.tripRef,
2111
+ listName: op.entity.listName,
2112
+ id: op.entity.id
1625
2113
  });
1626
- },
1627
- async manifest(options) {
1628
- const { token, signal } = options;
1629
- return client.execute({
1630
- method: "GET",
1631
- operationId: OperationId.GetShareManifest,
1632
- path: "/api/v1/share/{token}/manifest",
1633
- pathParams: { token },
1634
- ...signal !== void 0 ? { signal } : {}
2114
+ } catch {
2115
+ return { action: "deferred", body: void 0, currentVersion, current: void 0 };
2116
+ }
2117
+ if (read.status === 200 && read.entity !== void 0) {
2118
+ current = read.entity;
2119
+ await snapshot.upsert({
2120
+ tripRef: op.tripRef,
2121
+ listName: op.entity.listName,
2122
+ row: read.entity
1635
2123
  });
1636
- },
1637
- forms: {
1638
- async list(options) {
1639
- const { token, signal } = options;
1640
- return client.execute({
1641
- method: "GET",
1642
- operationId: OperationId.ShareListForms,
1643
- path: "/api/v1/share/{token}/forms",
1644
- pathParams: { token },
1645
- ...signal !== void 0 ? { signal } : {}
1646
- });
2124
+ }
2125
+ }
2126
+ const context = { op, currentVersion, current };
2127
+ const resolution = resolver === void 0 ? { action: "surface" } : await resolver(context);
2128
+ return {
2129
+ action: resolution.action,
2130
+ body: resolution.action === "reissue" ? resolution.body : void 0,
2131
+ currentVersion,
2132
+ current
2133
+ };
2134
+ }
2135
+
2136
+ // src/offline/transport.ts
2137
+ var BATCH_THRESHOLD_OPS = 5;
2138
+ var MAX_BATCH_OPS = 200;
2139
+ var CONSOLIDATED_PULL_THRESHOLD_LISTS = 3;
2140
+ function shouldUseBatchTransport(args) {
2141
+ return args.transport.sendBatch !== void 0 && args.readyCount >= BATCH_THRESHOLD_OPS;
2142
+ }
2143
+
2144
+ // src/offline/drainer.ts
2145
+ function userMessageFor(outcome) {
2146
+ if (outcome.code === "LOCKED" || outcome.status === 423) {
2147
+ return "This trip has been closed out, so this change was not saved.";
2148
+ }
2149
+ if (outcome.code === "FILE_PURGED" || outcome.status === 410) {
2150
+ return "That file is no longer available \u2014 its retention period has ended.";
2151
+ }
2152
+ if (outcome.code === "PLAN_FEATURE_DISABLED" || outcome.status === 402) {
2153
+ return "That feature is not included in this plan, so this change was not saved.";
2154
+ }
2155
+ if (outcome.code === "SHARE_WRITE_GRACE_EXPIRED") {
2156
+ return "This link expired \u2014 your submission was not delivered.";
2157
+ }
2158
+ if (outcome.status === 404) {
2159
+ return "That item is no longer available to you.";
2160
+ }
2161
+ if (outcome.status === 401) {
2162
+ return "Your session expired, so this change was not saved. Sign in again.";
2163
+ }
2164
+ return "This change could not be saved.";
2165
+ }
2166
+ function createDrainer(options) {
2167
+ const { outbox, snapshot, transport, events } = options;
2168
+ const now = options.now ?? Date.now;
2169
+ const random = options.random ?? Math.random;
2170
+ let inFlight = null;
2171
+ function observeServerTime(outcome) {
2172
+ if (outcome.serverTime !== void 0) {
2173
+ options.onServerTime?.(outcome.serverTime);
2174
+ }
2175
+ }
2176
+ async function applySuccess(op, outcome, state) {
2177
+ if (op.entity !== void 0 && outcome.entity !== void 0) {
2178
+ await snapshot.upsert({
2179
+ tripRef: op.tripRef,
2180
+ listName: op.entity.listName,
2181
+ row: outcome.entity,
2182
+ ...outcome.serverTime !== void 0 ? { syncedAt: outcome.serverTime } : {}
2183
+ });
2184
+ }
2185
+ await outbox.markDone(op.id);
2186
+ state.applied += 1;
2187
+ }
2188
+ async function park(op, outcome, state) {
2189
+ const message = userMessageFor(outcome);
2190
+ await outbox.park(op.id, {
2191
+ status: outcome.status,
2192
+ code: outcome.code,
2193
+ userMessage: message
2194
+ });
2195
+ state.parked += 1;
2196
+ events.emit("sync.error", {
2197
+ opId: op.id,
2198
+ tripRef: op.tripRef,
2199
+ error: outcome.error,
2200
+ status: outcome.status,
2201
+ parked: true,
2202
+ userMessage: message
2203
+ });
2204
+ }
2205
+ async function purgeIfCached(op, outcome) {
2206
+ if (op.entity === void 0) {
2207
+ return;
2208
+ }
2209
+ const held = snapshot.list(op.tripRef, op.entity.listName).some((row) => row.id === op.entity?.id);
2210
+ if (!held) {
2211
+ return;
2212
+ }
2213
+ if (outcome.status === 404 || outcome.status === 410) {
2214
+ await snapshot.purgeEntity(op.tripRef, op.entity.listName, op.entity.id);
2215
+ }
2216
+ }
2217
+ async function applyOutcome(op, outcome, state) {
2218
+ observeServerTime(outcome);
2219
+ if (outcome.status !== null && outcome.status >= 200 && outcome.status < 300) {
2220
+ await applySuccess(op, outcome, state);
2221
+ return "terminal";
2222
+ }
2223
+ if (outcome.status === 401 && !op.refreshAttempted) {
2224
+ await outbox.markRefreshAttempted(op.id);
2225
+ let refreshed = false;
2226
+ try {
2227
+ refreshed = await transport.refreshSession?.() === true;
2228
+ } catch {
2229
+ refreshed = false;
2230
+ }
2231
+ if (refreshed) {
2232
+ await outbox.requeue(op.id);
2233
+ return "pending";
2234
+ }
2235
+ events.emit("session.expired", { reason: "refresh-failed" });
2236
+ await park(op, outcome, state);
2237
+ return "terminal";
2238
+ }
2239
+ const verdict = classifyFailure({
2240
+ status: outcome.status,
2241
+ ...outcome.code !== void 0 ? { code: outcome.code } : {},
2242
+ ...outcome.transportFailureKind !== void 0 ? { transportFailureKind: outcome.transportFailureKind } : {}
2243
+ });
2244
+ if (verdict === "transient") {
2245
+ const delay = computeRetryDelayMs(op.attemptCount + 1, {
2246
+ ...outcome.retryAfterSeconds !== void 0 ? { retryAfterSeconds: outcome.retryAfterSeconds } : {},
2247
+ random
2248
+ });
2249
+ await outbox.scheduleRetry(op.id, now() + delay);
2250
+ events.emit("sync.error", {
2251
+ opId: op.id,
2252
+ tripRef: op.tripRef,
2253
+ error: outcome.error,
2254
+ status: outcome.status,
2255
+ parked: false
2256
+ });
2257
+ return "pending";
2258
+ }
2259
+ if (verdict === "conflict") {
2260
+ state.conflicted += 1;
2261
+ const result = await reconcileConflict({
2262
+ op,
2263
+ details: outcome.details,
2264
+ transport,
2265
+ snapshot,
2266
+ resolver: options.conflictResolver
2267
+ });
2268
+ switch (result.action) {
2269
+ case "drop":
2270
+ await outbox.drop(op.id);
2271
+ return "terminal";
2272
+ case "reissue":
2273
+ await outbox.reissue(op.id, {
2274
+ ...result.body !== void 0 ? { body: result.body } : {},
2275
+ ...result.currentVersion !== void 0 ? { ifMatch: result.currentVersion } : {}
2276
+ });
2277
+ return "pending";
2278
+ case "deferred":
2279
+ await outbox.requeue(op.id);
2280
+ return "pending";
2281
+ case "surface":
2282
+ await park(op, outcome, state);
2283
+ return "terminal";
2284
+ }
2285
+ }
2286
+ await purgeIfCached(op, outcome);
2287
+ await park(op, outcome, state);
2288
+ return "terminal";
2289
+ }
2290
+ async function drainLane(tripRef, state, signal) {
2291
+ for (; ; ) {
2292
+ if (signal?.aborted === true) {
2293
+ return;
2294
+ }
2295
+ const head = outbox.head(tripRef);
2296
+ if (head === void 0) {
2297
+ return;
2298
+ }
2299
+ if (head.nextRetryAt !== null && head.nextRetryAt > now()) {
2300
+ return;
2301
+ }
2302
+ const ready = outbox.readyPrefix(tripRef, now(), MAX_BATCH_OPS);
2303
+ if (ready.length === 0) {
2304
+ return;
2305
+ }
2306
+ if (shouldUseBatchTransport({ transport, readyCount: ready.length })) {
2307
+ state.usedBatch = true;
2308
+ const sent = await sendBatchedPrefix(ready, state, signal);
2309
+ if (!sent) {
2310
+ return;
2311
+ }
2312
+ continue;
2313
+ }
2314
+ await outbox.markInflight(head.id);
2315
+ let outcome;
2316
+ try {
2317
+ outcome = await transport.sendOne(head, signal);
2318
+ } catch (error) {
2319
+ outcome = {
2320
+ status: null,
2321
+ transportFailureKind: "network",
2322
+ ...isKaafilLike(error) ? { error } : {}
2323
+ };
2324
+ }
2325
+ const disposition = await applyOutcome(head, outcome, state);
2326
+ if (disposition === "pending") {
2327
+ const again = outbox.get(head.id);
2328
+ if (again !== void 0 && again.nextRetryAt !== null && again.nextRetryAt > now()) {
2329
+ return;
2330
+ }
2331
+ }
2332
+ }
2333
+ }
2334
+ async function sendBatchedPrefix(ready, state, signal) {
2335
+ const sendBatch = transport.sendBatch;
2336
+ if (sendBatch === void 0) {
2337
+ return false;
2338
+ }
2339
+ for (const op of ready) {
2340
+ await outbox.markInflight(op.id);
2341
+ }
2342
+ let outcomes;
2343
+ try {
2344
+ outcomes = await sendBatch(ready, signal);
2345
+ } catch {
2346
+ const [head, ...rest] = ready;
2347
+ if (head !== void 0) {
2348
+ await outbox.scheduleRetry(
2349
+ head.id,
2350
+ now() + computeRetryDelayMs(head.attemptCount + 1, { random })
2351
+ );
2352
+ }
2353
+ for (const op of rest) {
2354
+ await outbox.requeue(op.id);
2355
+ }
2356
+ return false;
2357
+ }
2358
+ let halted = false;
2359
+ for (let index = 0; index < ready.length; index += 1) {
2360
+ const op = ready[index];
2361
+ if (op === void 0) {
2362
+ continue;
2363
+ }
2364
+ if (halted) {
2365
+ await outbox.requeue(op.id);
2366
+ continue;
2367
+ }
2368
+ const outcome = outcomes[index];
2369
+ if (outcome === void 0) {
2370
+ await outbox.requeue(op.id);
2371
+ halted = true;
2372
+ continue;
2373
+ }
2374
+ const disposition = await applyOutcome(op, outcome, state);
2375
+ if (disposition === "pending") {
2376
+ halted = true;
2377
+ }
2378
+ }
2379
+ return !halted;
2380
+ }
2381
+ async function runPass(signal) {
2382
+ const state = { applied: 0, parked: 0, conflicted: 0, usedBatch: false };
2383
+ const lanes = outbox.lanes();
2384
+ await Promise.all(lanes.map((tripRef) => drainLane(tripRef, state, signal)));
2385
+ const report = {
2386
+ applied: state.applied,
2387
+ parked: state.parked,
2388
+ conflicted: state.conflicted,
2389
+ remaining: outbox.counts().pending,
2390
+ usedBatchTransport: state.usedBatch,
2391
+ lanes
2392
+ };
2393
+ events.emit("sync.drained", {
2394
+ applied: report.applied,
2395
+ parked: report.parked,
2396
+ conflicted: report.conflicted,
2397
+ remaining: report.remaining,
2398
+ usedBatchTransport: report.usedBatchTransport
2399
+ });
2400
+ return report;
2401
+ }
2402
+ const drainer = {
2403
+ async drain(drainOptions = {}) {
2404
+ if (inFlight !== null) {
2405
+ return inFlight;
2406
+ }
2407
+ const pass = runPass(drainOptions.signal).finally(() => {
2408
+ inFlight = null;
2409
+ });
2410
+ inFlight = pass;
2411
+ return pass;
2412
+ },
2413
+ kick() {
2414
+ void drainer.drain().catch(() => {
2415
+ });
2416
+ },
2417
+ bindOpportunisticTriggers() {
2418
+ const target = typeof globalThis.addEventListener === "function" ? globalThis : void 0;
2419
+ if (target === void 0) {
2420
+ return () => {
2421
+ };
2422
+ }
2423
+ const onOnline = () => {
2424
+ drainer.kick();
2425
+ };
2426
+ const onVisible = () => {
2427
+ const state = globalThis.document?.visibilityState;
2428
+ if (state === void 0 || state === "visible") {
2429
+ drainer.kick();
2430
+ }
2431
+ };
2432
+ target.addEventListener("online", onOnline);
2433
+ target.addEventListener("visibilitychange", onVisible);
2434
+ target.addEventListener("focus", onVisible);
2435
+ return () => {
2436
+ target.removeEventListener("online", onOnline);
2437
+ target.removeEventListener("visibilitychange", onVisible);
2438
+ target.removeEventListener("focus", onVisible);
2439
+ };
2440
+ }
2441
+ };
2442
+ return drainer;
2443
+ }
2444
+ function isKaafilLike(error) {
2445
+ return typeof error === "object" && error !== null && "kind" in error && error instanceof Error;
2446
+ }
2447
+
2448
+ // src/offline/events.ts
2449
+ function createOfflineEvents(options = {}) {
2450
+ const handlers = /* @__PURE__ */ new Map();
2451
+ return {
2452
+ on(name, handler) {
2453
+ let set = handlers.get(name);
2454
+ if (set === void 0) {
2455
+ set = /* @__PURE__ */ new Set();
2456
+ handlers.set(name, set);
2457
+ }
2458
+ set.add(handler);
2459
+ let removed = false;
2460
+ return () => {
2461
+ if (removed) {
2462
+ return;
2463
+ }
2464
+ removed = true;
2465
+ set?.delete(handler);
2466
+ };
2467
+ },
2468
+ emit(name, event) {
2469
+ const set = handlers.get(name);
2470
+ if (set === void 0) {
2471
+ return;
2472
+ }
2473
+ for (const handler of [...set]) {
2474
+ try {
2475
+ handler(event);
2476
+ } catch (error) {
2477
+ options.onHandlerError?.(error, name);
2478
+ }
2479
+ }
2480
+ },
2481
+ clear() {
2482
+ handlers.clear();
2483
+ }
2484
+ };
2485
+ }
2486
+
2487
+ // src/offline/pull.ts
2488
+ var SYNC_PULL_SECTIONS = [
2489
+ "rooming",
2490
+ "stayWindows",
2491
+ "pickups",
2492
+ "seating",
2493
+ "bookings",
2494
+ "expenses",
2495
+ "checklist",
2496
+ "float",
2497
+ "collections",
2498
+ "itinerary",
2499
+ "closeout"
2500
+ ];
2501
+ function extractSectionRows(data) {
2502
+ if (Array.isArray(data)) {
2503
+ return isRowArray(data) ? data : void 0;
2504
+ }
2505
+ if (typeof data !== "object" || data === null) {
2506
+ return void 0;
2507
+ }
2508
+ let found;
2509
+ for (const value of Object.values(data)) {
2510
+ if (!Array.isArray(value) || !isRowArray(value)) {
2511
+ continue;
2512
+ }
2513
+ if (found !== void 0) {
2514
+ return void 0;
2515
+ }
2516
+ found = value;
2517
+ }
2518
+ return found;
2519
+ }
2520
+ function isRowArray(value) {
2521
+ return value.every(
2522
+ (item) => typeof item === "object" && item !== null && typeof item.id === "string"
2523
+ );
2524
+ }
2525
+ function createPullCoordinator(options) {
2526
+ const { snapshot, transport, events } = options;
2527
+ function sinceFor(tripRef) {
2528
+ const known = snapshot.listNames(tripRef).filter(
2529
+ (name) => SYNC_PULL_SECTIONS.includes(name)
2530
+ );
2531
+ if (known.length === 0) {
2532
+ return void 0;
2533
+ }
2534
+ let min;
2535
+ for (const name of known) {
2536
+ const cursor = snapshot.cursor(tripRef, name);
2537
+ if (cursor === void 0) {
2538
+ return void 0;
2539
+ }
2540
+ if (min === void 0 || cursor < min) {
2541
+ min = cursor;
2542
+ }
2543
+ }
2544
+ return min;
2545
+ }
2546
+ async function applyOnce(tripRef, since, signal) {
2547
+ const pullTripFn = transport.pullTrip;
2548
+ if (pullTripFn === void 0) {
2549
+ throw new TypeError(
2550
+ "This offline engine was built without a consolidated-pull transport, so pullTrip() has nothing to call. Supply OfflineTransport.pullTrip."
2551
+ );
2552
+ }
2553
+ const response = await pullTripFn({
2554
+ tripRef,
2555
+ since,
2556
+ ...signal !== void 0 ? { signal } : {}
2557
+ });
2558
+ const serverTime = response.serverTime;
2559
+ options.onServerTime?.(serverTime);
2560
+ const present = [];
2561
+ const absent = [];
2562
+ const unmapped = [];
2563
+ const changed = [];
2564
+ let coldRepullNeeded = false;
2565
+ for (const name of SYNC_PULL_SECTIONS) {
2566
+ const section = response.sections[name];
2567
+ if (section === void 0) {
2568
+ absent.push(name);
2569
+ continue;
2570
+ }
2571
+ const rows = extractSectionRows(section.data);
2572
+ if (rows === void 0) {
2573
+ unmapped.push(name);
2574
+ continue;
2575
+ }
2576
+ present.push(name);
2577
+ const hadCursor = snapshot.cursor(tripRef, name) !== void 0;
2578
+ if (!hadCursor && since !== void 0) {
2579
+ coldRepullNeeded = true;
2580
+ }
2581
+ const applied = await snapshot.applyPull({ tripRef, listName: name, rows, serverTime });
2582
+ if (applied.changed) {
2583
+ changed.push(name);
2584
+ }
2585
+ }
2586
+ if (changed.length > 0) {
2587
+ events.emit("snapshot.updated", { tripRef, lists: changed, serverTime });
2588
+ }
2589
+ return {
2590
+ result: { tripRef, serverTime, present, absent, unmapped, changed, coldRepulled: false },
2591
+ coldRepullNeeded
2592
+ };
2593
+ }
2594
+ return {
2595
+ sinceFor,
2596
+ async pullTrip({ tripRef, signal, cold }) {
2597
+ const since = cold === true ? void 0 : sinceFor(tripRef);
2598
+ const first = await applyOnce(tripRef, since, signal);
2599
+ if (!first.coldRepullNeeded) {
2600
+ return first.result;
2601
+ }
2602
+ const second = await applyOnce(tripRef, void 0, signal);
2603
+ return { ...second.result, coldRepulled: true };
2604
+ }
2605
+ };
2606
+ }
2607
+
2608
+ // src/offline/share.ts
2609
+ var SHARE_WRITE_GRACE_MS = 7 * 24 * 60 * 60 * 1e3;
2610
+ var KaafilShareLinkExpiredError = class _KaafilShareLinkExpiredError extends Error {
2611
+ constructor() {
2612
+ super("This link has expired, so it can no longer be used to view or submit anything.");
2613
+ this.name = "KaafilShareLinkExpiredError";
2614
+ Object.setPrototypeOf(this, _KaafilShareLinkExpiredError.prototype);
2615
+ }
2616
+ };
2617
+ function defaultMonotonicClock() {
2618
+ const performanceNow = globalThis.performance?.now;
2619
+ if (typeof performanceNow === "function") {
2620
+ return () => performanceNow.call(globalThis.performance);
2621
+ }
2622
+ let ticks = 0;
2623
+ return () => {
2624
+ ticks += 1;
2625
+ return ticks;
2626
+ };
2627
+ }
2628
+ function createShareGuard(options) {
2629
+ const monotonic = options.monotonic ?? defaultMonotonicClock();
2630
+ const expiresAtMs = Date.parse(options.expiresAt);
2631
+ let anchor;
2632
+ function estimateNow() {
2633
+ if (anchor === void 0) {
2634
+ return void 0;
2635
+ }
2636
+ return anchor.serverMs + Math.max(0, monotonic() - anchor.monotonicMs);
2637
+ }
2638
+ const guard = {
2639
+ observeServerTime(serverTime) {
2640
+ const parsed = Date.parse(serverTime);
2641
+ if (Number.isNaN(parsed)) {
2642
+ return;
2643
+ }
2644
+ if (anchor !== void 0 && parsed <= anchor.serverMs) {
2645
+ return;
2646
+ }
2647
+ anchor = { serverMs: parsed, monotonicMs: monotonic() };
2648
+ },
2649
+ now() {
2650
+ return estimateNow();
2651
+ },
2652
+ isExpired() {
2653
+ const at = estimateNow();
2654
+ if (at === void 0 || Number.isNaN(expiresAtMs)) {
2655
+ return false;
2656
+ }
2657
+ return at >= expiresAtMs;
2658
+ },
2659
+ isGraceClosed() {
2660
+ const at = estimateNow();
2661
+ if (at === void 0 || Number.isNaN(expiresAtMs)) {
2662
+ return false;
2663
+ }
2664
+ return at >= expiresAtMs + SHARE_WRITE_GRACE_MS;
2665
+ },
2666
+ assertWritable() {
2667
+ if (guard.isExpired()) {
2668
+ throw new KaafilShareLinkExpiredError();
2669
+ }
2670
+ },
2671
+ async invalidate(reason, code) {
2672
+ await options.snapshot.purgeTrip(options.tripRef);
2673
+ const preserved = options.outbox.counts().pending;
2674
+ const payload = {
2675
+ code: code === KaafilErrorCode.ShareTokenExpired || code === KaafilErrorCode.ShareTokenRevoked ? code : void 0,
2676
+ snapshotPurged: true,
2677
+ pendingOpsPreserved: preserved
2678
+ };
2679
+ options.events.emit(reason === "expired" ? "share.expired" : "share.revoked", payload);
2680
+ },
2681
+ async applyPreflight(result) {
2682
+ if (result.code === KaafilErrorCode.ShareTokenRevoked) {
2683
+ await guard.invalidate("revoked", result.code);
2684
+ return "revoked";
2685
+ }
2686
+ if (result.code === KaafilErrorCode.ShareTokenExpired) {
2687
+ await guard.invalidate("expired", result.code);
2688
+ return "expired";
2689
+ }
2690
+ return "valid";
2691
+ },
2692
+ async parkOpsPastGrace() {
2693
+ if (!guard.isGraceClosed()) {
2694
+ return 0;
2695
+ }
2696
+ let parked = 0;
2697
+ for (const op of options.outbox.all()) {
2698
+ if (op.status !== "pending") {
2699
+ continue;
2700
+ }
2701
+ await options.outbox.park(op.id, {
2702
+ status: null,
2703
+ code: KaafilErrorCode.ShareWriteGraceExpired,
2704
+ userMessage: "This link expired \u2014 your submission was not delivered."
2705
+ });
2706
+ parked += 1;
2707
+ options.events.emit("sync.error", {
2708
+ opId: op.id,
2709
+ tripRef: op.tripRef,
2710
+ error: void 0,
2711
+ status: null,
2712
+ parked: true,
2713
+ userMessage: "This link expired \u2014 your submission was not delivered."
2714
+ });
2715
+ }
2716
+ return parked;
2717
+ }
2718
+ };
2719
+ return guard;
2720
+ }
2721
+
2722
+ // src/datetime.ts
2723
+ var FULL_DATETIME_WITH_OFFSET = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
2724
+ var DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
2725
+ function invalidRequest(fieldPath, message) {
2726
+ return new KaafilInvalidRequestError(`${fieldPath}: ${message}`);
2727
+ }
2728
+ function normalizeDateTimeInput(value, fieldPath) {
2729
+ if (value instanceof Date) {
2730
+ if (Number.isNaN(value.getTime())) {
2731
+ throw invalidRequest(fieldPath, "received an invalid Date (getTime() is NaN).");
2732
+ }
2733
+ return value.toISOString();
2734
+ }
2735
+ if (typeof value === "number") {
2736
+ if (!Number.isFinite(value)) {
2737
+ throw invalidRequest(
2738
+ fieldPath,
2739
+ `received a non-finite number (${String(value)}); expected epoch milliseconds.`
2740
+ );
2741
+ }
2742
+ return new Date(value).toISOString();
2743
+ }
2744
+ if (FULL_DATETIME_WITH_OFFSET.test(value)) {
2745
+ return value;
2746
+ }
2747
+ if (DATE_ONLY.test(value)) {
2748
+ throw invalidRequest(
2749
+ fieldPath,
2750
+ `received a date-only string ("${value}"). This API requires a full ISO-8601 datetime WITH an offset, and the SDK will not guess which timezone you meant (midnight UTC is rarely midnight where the trip actually starts). Pass a \`Date\` instead \u2014 e.g. \`new Date("2026-08-20T09:00:00+05:30")\` \u2014 or add an explicit offset yourself, e.g. "2026-08-20T00:00:00+05:30".`
2751
+ );
2752
+ }
2753
+ throw invalidRequest(
2754
+ fieldPath,
2755
+ `received "${value}", which is not a full ISO-8601 datetime with an offset. Pass a \`Date\`, an epoch-milliseconds number, or a string like "2026-08-20T09:00:00+05:30".`
2756
+ );
2757
+ }
2758
+ function normalizeNullableDateTimeInput(value, fieldPath) {
2759
+ return value === null ? null : normalizeDateTimeInput(value, fieldPath);
2760
+ }
2761
+
2762
+ // src/delta/cursor.ts
2763
+ function isTombstone(row) {
2764
+ return row._tombstone === true;
2765
+ }
2766
+ function mergeDeltaRows(store, rows) {
2767
+ let added = 0;
2768
+ let updated = 0;
2769
+ let removed = 0;
2770
+ let unchanged = 0;
2771
+ for (const row of rows) {
2772
+ const held = store.get(row.id);
2773
+ if (isTombstone(row)) {
2774
+ if (held === void 0 || held.version > row.version) {
2775
+ unchanged += 1;
2776
+ continue;
2777
+ }
2778
+ store.delete(row.id);
2779
+ removed += 1;
2780
+ continue;
2781
+ }
2782
+ if (held === void 0) {
2783
+ store.set(row.id, row);
2784
+ added += 1;
2785
+ continue;
2786
+ }
2787
+ if (held.version >= row.version) {
2788
+ unchanged += 1;
2789
+ continue;
2790
+ }
2791
+ store.set(row.id, row);
2792
+ updated += 1;
2793
+ }
2794
+ return { added, updated, removed, unchanged };
2795
+ }
2796
+ var KaafilDeltaCursorInFlightError = class _KaafilDeltaCursorInFlightError extends Error {
2797
+ constructor() {
2798
+ super(
2799
+ "pull() was called while a previous pull on this delta cursor was still in flight. Two concurrent pulls would settle in an unknown order and leave the cursor at whichever response landed last, not the newest \u2014 await the first one's result."
2800
+ );
2801
+ this.name = "KaafilDeltaCursorInFlightError";
2802
+ Object.setPrototypeOf(this, _KaafilDeltaCursorInFlightError.prototype);
2803
+ }
2804
+ };
2805
+ function createDeltaCursor(config) {
2806
+ const { fetchDelta } = config;
2807
+ const state = {
2808
+ cursor: void 0,
2809
+ isLoading: false
2810
+ };
2811
+ function restore(cursor) {
2812
+ state.cursor = normalizeDateTimeInput(cursor, "cursor");
2813
+ }
2814
+ if (config.cursor !== void 0) {
2815
+ restore(config.cursor);
2816
+ }
2817
+ async function pull(options = {}) {
2818
+ if (state.isLoading) {
2819
+ throw new KaafilDeltaCursorInFlightError();
2820
+ }
2821
+ const previousCursor = state.cursor;
2822
+ state.isLoading = true;
2823
+ try {
2824
+ const response = await fetchDelta({ since: previousCursor, signal: options.signal });
2825
+ state.cursor = response.meta.serverTime;
2826
+ return {
2827
+ data: response,
2828
+ meta: response.meta,
2829
+ cursor: response.meta.serverTime,
2830
+ previousCursor
2831
+ };
2832
+ } finally {
2833
+ state.isLoading = false;
2834
+ }
2835
+ }
2836
+ return {
2837
+ get cursor() {
2838
+ return state.cursor;
2839
+ },
2840
+ get isLoading() {
2841
+ return state.isLoading;
2842
+ },
2843
+ get hasSynced() {
2844
+ return state.cursor !== void 0;
2845
+ },
2846
+ pull,
2847
+ restore,
2848
+ reset() {
2849
+ state.cursor = void 0;
2850
+ }
2851
+ };
2852
+ }
2853
+
2854
+ // src/offline/snapshot.ts
2855
+ var EMPTY_LIST = { cursor: void 0, rows: {}, syncedAt: {} };
2856
+ function createSnapshotStore(options) {
2857
+ const key = `${options.keyPrefix}:snapshot`;
2858
+ let trips = /* @__PURE__ */ new Map();
2859
+ async function persist() {
2860
+ const shape = { trips: {} };
2861
+ for (const [tripRef, lists] of trips) {
2862
+ const out = {};
2863
+ for (const [listName, value] of lists) {
2864
+ out[listName] = value;
2865
+ }
2866
+ shape.trips[tripRef] = out;
2867
+ }
2868
+ await options.storage.set(key, JSON.stringify(shape));
2869
+ }
2870
+ function getList(tripRef, listName) {
2871
+ return trips.get(tripRef)?.get(listName) ?? EMPTY_LIST;
2872
+ }
2873
+ function setList(tripRef, listName, value) {
2874
+ let lists = trips.get(tripRef);
2875
+ if (lists === void 0) {
2876
+ lists = /* @__PURE__ */ new Map();
2877
+ trips.set(tripRef, lists);
2878
+ }
2879
+ lists.set(listName, value);
2880
+ }
2881
+ return {
2882
+ async load() {
2883
+ const raw = await options.storage.get(key);
2884
+ trips = /* @__PURE__ */ new Map();
2885
+ if (raw === void 0) {
2886
+ return;
2887
+ }
2888
+ let parsed;
2889
+ try {
2890
+ parsed = JSON.parse(raw);
2891
+ } catch {
2892
+ return;
2893
+ }
2894
+ for (const [tripRef, lists] of Object.entries(parsed.trips ?? {})) {
2895
+ for (const [listName, value] of Object.entries(lists)) {
2896
+ setList(tripRef, listName, {
2897
+ cursor: value.cursor,
2898
+ rows: value.rows ?? {},
2899
+ syncedAt: value.syncedAt ?? {}
2900
+ });
2901
+ }
2902
+ }
2903
+ },
2904
+ list(tripRef, listName) {
2905
+ return Object.values(getList(tripRef, listName).rows);
2906
+ },
2907
+ cursor(tripRef, listName) {
2908
+ return getList(tripRef, listName).cursor;
2909
+ },
2910
+ syncedAt(tripRef, listName, id) {
2911
+ return getList(tripRef, listName).syncedAt[id];
2912
+ },
2913
+ listNames(tripRef) {
2914
+ return [...trips.get(tripRef)?.keys() ?? []];
2915
+ },
2916
+ async applyPull({ tripRef, listName, rows, serverTime }) {
2917
+ const current = getList(tripRef, listName);
2918
+ const merged = new Map(Object.entries(current.rows));
2919
+ const stats = mergeDeltaRows(merged, rows);
2920
+ const syncedAt = {};
2921
+ for (const id of merged.keys()) {
2922
+ syncedAt[id] = current.rows[id] === merged.get(id) ? current.syncedAt[id] ?? serverTime : serverTime;
2923
+ }
2924
+ setList(tripRef, listName, {
2925
+ cursor: serverTime,
2926
+ rows: Object.fromEntries(merged),
2927
+ syncedAt
2928
+ });
2929
+ await persist();
2930
+ return {
2931
+ stats,
2932
+ // Derived from what the merge DID, not from `rows.length` — an
2933
+ // at-least-once window routinely re-delivers rows that change
2934
+ // nothing, and counting them would report a change that never
2935
+ // happened (`06 §5`).
2936
+ changed: stats.added + stats.updated + stats.removed > 0,
2937
+ cursor: serverTime
2938
+ };
2939
+ },
2940
+ async upsert({ tripRef, listName, row, syncedAt }) {
2941
+ const current = getList(tripRef, listName);
2942
+ const held = current.rows[row.id];
2943
+ if (held !== void 0 && held.version > row.version) {
2944
+ return false;
2945
+ }
2946
+ setList(tripRef, listName, {
2947
+ cursor: current.cursor,
2948
+ rows: { ...current.rows, [row.id]: row },
2949
+ syncedAt: syncedAt !== void 0 ? { ...current.syncedAt, [row.id]: syncedAt } : current.syncedAt
2950
+ });
2951
+ await persist();
2952
+ return true;
2953
+ },
2954
+ async purgeEntity(tripRef, listName, id) {
2955
+ const current = getList(tripRef, listName);
2956
+ if (current.rows[id] === void 0) {
2957
+ return;
2958
+ }
2959
+ const rows = { ...current.rows };
2960
+ const stamps = { ...current.syncedAt };
2961
+ delete rows[id];
2962
+ delete stamps[id];
2963
+ setList(tripRef, listName, { cursor: current.cursor, rows, syncedAt: stamps });
2964
+ await persist();
2965
+ },
2966
+ async purgeTrip(tripRef) {
2967
+ if (!trips.delete(tripRef)) {
2968
+ return;
2969
+ }
2970
+ await persist();
2971
+ }
2972
+ };
2973
+ }
2974
+
2975
+ // src/offline/engine.ts
2976
+ function createOfflineEngine(options) {
2977
+ const keyPrefix = `kaafil:v1:${options.scope}`;
2978
+ const events = createOfflineEvents({
2979
+ ...options.onEventHandlerError !== void 0 ? { onHandlerError: (error) => options.onEventHandlerError?.(error) } : {}
2980
+ });
2981
+ const snapshot = createSnapshotStore({ storage: options.storage, keyPrefix });
2982
+ const outbox = createOutbox({
2983
+ storage: options.storage,
2984
+ keyPrefix,
2985
+ ...options.now !== void 0 ? { now: options.now } : {},
2986
+ ...options.newId !== void 0 ? { newId: options.newId } : {}
2987
+ });
2988
+ let share;
2989
+ const onServerTime = (serverTime) => {
2990
+ share?.observeServerTime(serverTime);
2991
+ };
2992
+ if (options.share !== void 0) {
2993
+ share = createShareGuard({
2994
+ tripRef: options.share.tripRef,
2995
+ expiresAt: options.share.expiresAt,
2996
+ snapshot,
2997
+ outbox,
2998
+ events,
2999
+ ...options.share.monotonic !== void 0 ? { monotonic: options.share.monotonic } : {}
3000
+ });
3001
+ }
3002
+ const drainer = createDrainer({
3003
+ outbox,
3004
+ snapshot,
3005
+ transport: options.transport,
3006
+ events,
3007
+ onServerTime,
3008
+ ...options.conflictResolver !== void 0 ? { conflictResolver: options.conflictResolver } : {},
3009
+ ...options.now !== void 0 ? { now: options.now } : {},
3010
+ ...options.random !== void 0 ? { random: options.random } : {}
3011
+ });
3012
+ const pull = createPullCoordinator({
3013
+ snapshot,
3014
+ transport: options.transport,
3015
+ events,
3016
+ onServerTime
3017
+ });
3018
+ const blobs = options.blob === void 0 ? void 0 : createBlobLane({
3019
+ storage: options.storage,
3020
+ keyPrefix,
3021
+ outbox,
3022
+ uploader: options.blob.uploader,
3023
+ source: options.blob.source,
3024
+ ...options.now !== void 0 ? { now: options.now } : {},
3025
+ ...options.random !== void 0 ? { random: options.random } : {}
3026
+ });
3027
+ let unbind;
3028
+ async function enqueue(input) {
3029
+ share?.assertWritable();
3030
+ const op = await outbox.enqueue({
3031
+ tripRef: input.tripRef,
3032
+ method: input.method,
3033
+ path: input.path,
3034
+ operationId: input.operationId,
3035
+ ...input.body !== void 0 ? { body: input.body } : {},
3036
+ ...input.ifMatch !== void 0 ? { ifMatch: input.ifMatch } : {},
3037
+ ...input.entity !== void 0 ? { entity: input.entity } : {},
3038
+ ...input.idempotencyKey !== void 0 ? { idempotencyKey: input.idempotencyKey } : {},
3039
+ ...input.enqueuedAt !== void 0 ? { enqueuedAt: input.enqueuedAt } : {}
3040
+ });
3041
+ if (input.optimistic !== void 0 && input.entity !== void 0) {
3042
+ await snapshot.upsert({
3043
+ tripRef: input.tripRef,
3044
+ listName: input.entity.listName,
3045
+ row: input.optimistic
3046
+ });
3047
+ }
3048
+ drainer.kick();
3049
+ return op;
3050
+ }
3051
+ return {
3052
+ events,
3053
+ snapshot,
3054
+ outbox,
3055
+ drainer,
3056
+ pull,
3057
+ blobs,
3058
+ share,
3059
+ async open() {
3060
+ await Promise.all([snapshot.load(), outbox.load(), blobs?.load() ?? Promise.resolve()]);
3061
+ unbind = drainer.bindOpportunisticTriggers();
3062
+ },
3063
+ enqueue,
3064
+ async enqueueWithBlob(input) {
3065
+ const { blob, ...rest } = input;
3066
+ share?.assertWritable();
3067
+ const op = await outbox.enqueue({
3068
+ tripRef: rest.tripRef,
3069
+ method: rest.method,
3070
+ path: rest.path,
3071
+ operationId: rest.operationId,
3072
+ receiptPending: true,
3073
+ blobId: blob.id,
3074
+ ...rest.body !== void 0 ? { body: rest.body } : {},
3075
+ ...rest.ifMatch !== void 0 ? { ifMatch: rest.ifMatch } : {},
3076
+ ...rest.entity !== void 0 ? { entity: rest.entity } : {},
3077
+ ...rest.idempotencyKey !== void 0 ? { idempotencyKey: rest.idempotencyKey } : {},
3078
+ ...rest.enqueuedAt !== void 0 ? { enqueuedAt: rest.enqueuedAt } : {}
3079
+ });
3080
+ if (rest.optimistic !== void 0 && rest.entity !== void 0) {
3081
+ await snapshot.upsert({
3082
+ tripRef: rest.tripRef,
3083
+ listName: rest.entity.listName,
3084
+ row: rest.optimistic
3085
+ });
3086
+ }
3087
+ if (blobs !== void 0) {
3088
+ await blobs.enqueue({
3089
+ blobId: blob.id,
3090
+ tripRef: rest.tripRef,
3091
+ parentOpId: op.id,
3092
+ contentType: blob.contentType,
3093
+ sizeBytes: blob.sizeBytes,
3094
+ backfill: blob.backfill
3095
+ });
3096
+ }
3097
+ drainer.kick();
3098
+ return op;
3099
+ },
3100
+ async drain() {
3101
+ await share?.parkOpsPastGrace();
3102
+ const report = await drainer.drain();
3103
+ await blobs?.drain();
3104
+ return report;
3105
+ },
3106
+ close() {
3107
+ unbind?.();
3108
+ unbind = void 0;
3109
+ events.clear();
3110
+ }
3111
+ };
3112
+ }
3113
+ function outcomeFromError(error) {
3114
+ if (isKaafilError(error)) {
3115
+ const kaafil = error;
3116
+ return {
3117
+ status: kaafil.status ?? null,
3118
+ ...kaafil.code !== void 0 ? { code: kaafil.code } : {},
3119
+ ...kaafil.details !== void 0 ? { details: kaafil.details } : {},
3120
+ ...kaafil.meta?.serverTime !== void 0 ? { serverTime: kaafil.meta.serverTime } : {},
3121
+ error: kaafil
3122
+ };
3123
+ }
3124
+ return { status: null, transportFailureKind: "network" };
3125
+ }
3126
+ function entityFromBody(body) {
3127
+ if (typeof body !== "object" || body === null) {
3128
+ return void 0;
3129
+ }
3130
+ const candidate = body;
3131
+ if (typeof candidate.id === "string" && typeof candidate.version === "number") {
3132
+ return body;
3133
+ }
3134
+ return void 0;
3135
+ }
3136
+ function createHttpOfflineTransport(options) {
3137
+ const { http, sync } = options;
3138
+ const batchable = options.credential !== "share" || isShareBatchPushAvailable();
3139
+ const transport = {
3140
+ async sendOne(op, signal) {
3141
+ try {
3142
+ const response = await http.execute({
3143
+ method: op.method,
3144
+ operationId: op.operationId,
3145
+ path: op.path,
3146
+ // The op's OWN key, fixed at enqueue and reused on every attempt.
3147
+ idempotencyKey: op.idempotencyKey,
3148
+ ...op.body !== void 0 ? { body: op.body } : {},
3149
+ ...op.ifMatch !== void 0 ? { headers: { "If-Match": String(op.ifMatch) } } : {},
3150
+ ...signal !== void 0 ? { signal } : {}
3151
+ });
3152
+ const { meta, ...data } = response;
3153
+ const entity = entityFromBody(data);
3154
+ return {
3155
+ status: meta.status,
3156
+ serverTime: meta.serverTime,
3157
+ ...entity !== void 0 ? { entity } : {}
3158
+ };
3159
+ } catch (error) {
3160
+ return outcomeFromError(error);
3161
+ }
3162
+ },
3163
+ ...options.readEntity !== void 0 ? { readEntity: options.readEntity } : {},
3164
+ async pullTrip({ tripRef, since, signal }) {
3165
+ const response = await sync.pullTrip({
3166
+ tripRef,
3167
+ ...since !== void 0 ? { since } : {},
3168
+ ...signal !== void 0 ? { signal } : {}
3169
+ });
3170
+ return {
3171
+ tripRef: response.tripRef,
3172
+ // `sections` is a PARTIAL record and stays one all the way through —
3173
+ // nothing here fills a missing key with an empty list (`./pull.ts`).
3174
+ sections: response.sections,
3175
+ serverTime: response.meta.serverTime
3176
+ };
3177
+ }
3178
+ };
3179
+ if (!batchable) {
3180
+ return transport;
3181
+ }
3182
+ return {
3183
+ ...transport,
3184
+ async sendBatch(ops, signal) {
3185
+ const push = options.credential === "share" ? sync.pushShare : sync.push;
3186
+ const response = await push({
3187
+ ops: ops.map((op) => ({
3188
+ method: op.method,
3189
+ path: op.path,
3190
+ idempotencyKey: op.idempotencyKey,
3191
+ ...op.ifMatch !== void 0 ? { ifMatch: op.ifMatch } : {},
3192
+ ...op.enqueuedAt !== void 0 ? { enqueuedAt: op.enqueuedAt } : {},
3193
+ ...op.body !== void 0 ? { body: op.body } : {}
3194
+ })),
3195
+ ...signal !== void 0 ? { signal } : {}
3196
+ });
3197
+ const serverTime = response.meta.serverTime;
3198
+ const byIndex = new Map(response.verdicts.map((verdict) => [verdict.index, verdict]));
3199
+ return ops.map((_op, index) => {
3200
+ const verdict = byIndex.get(index);
3201
+ if (verdict === void 0) {
3202
+ return { status: null, transportFailureKind: "network" };
3203
+ }
3204
+ const envelope = verdict.body;
3205
+ if (verdict.status >= 200 && verdict.status < 300) {
3206
+ const entity = entityFromBody(envelope?.data);
3207
+ return {
3208
+ status: verdict.status,
3209
+ serverTime,
3210
+ ...entity !== void 0 ? { entity } : {}
3211
+ };
3212
+ }
3213
+ const code = envelope?.error?.code;
3214
+ const details = envelope?.error?.details;
3215
+ return {
3216
+ status: verdict.status,
3217
+ serverTime,
3218
+ ...typeof code === "string" && code in KaafilErrorCodeValues ? { code } : {},
3219
+ ...typeof details === "object" && details !== null ? { details } : {}
3220
+ };
3221
+ });
3222
+ }
3223
+ };
3224
+ }
3225
+ var KaafilErrorCodeValues = Object.fromEntries(
3226
+ Object.values(KaafilErrorCode).map((code) => [code, true])
3227
+ );
3228
+
3229
+ // src/resources/checklists.ts
3230
+ function createChecklistsResource(client) {
3231
+ return {
3232
+ async read(options) {
3233
+ const { tripRef, since, signal } = options;
3234
+ return client.execute({
3235
+ method: "GET",
3236
+ operationId: OperationId.ReadChecklistAggregate,
3237
+ path: "/api/v1/trips/{ref}/checklist",
3238
+ pathParams: { ref: tripRef },
3239
+ query: { since },
3240
+ ...signal !== void 0 ? { signal } : {}
3241
+ });
3242
+ },
3243
+ items: {
3244
+ async add(options) {
3245
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3246
+ return client.execute({
3247
+ method: "POST",
3248
+ operationId: OperationId.AddChecklistItem,
3249
+ path: "/api/v1/trips/{ref}/checklist/items",
3250
+ pathParams: { ref: tripRef },
3251
+ body,
3252
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3253
+ ...signal !== void 0 ? { signal } : {}
3254
+ });
3255
+ },
3256
+ async patch(options) {
3257
+ const { tripRef, itemId, version, signal, ...body } = options;
3258
+ return client.execute({
3259
+ method: "PATCH",
3260
+ operationId: OperationId.PatchChecklistItem,
3261
+ path: "/api/v1/trips/{ref}/checklist/items/{itemId}",
3262
+ pathParams: { ref: tripRef, itemId },
3263
+ body,
3264
+ headers: { "If-Match": String(version) },
3265
+ ...signal !== void 0 ? { signal } : {}
3266
+ });
3267
+ },
3268
+ async remove(options) {
3269
+ const { tripRef, itemId, version, signal } = options;
3270
+ return client.execute({
3271
+ method: "DELETE",
3272
+ operationId: OperationId.DeleteChecklistItem,
3273
+ path: "/api/v1/trips/{ref}/checklist/items/{itemId}",
3274
+ pathParams: { ref: tripRef, itemId },
3275
+ headers: { "If-Match": String(version) },
3276
+ ...signal !== void 0 ? { signal } : {}
3277
+ });
3278
+ },
3279
+ async toggle(options) {
3280
+ const { tripRef, itemId, idempotencyKey, signal, ...body } = options;
3281
+ return client.execute({
3282
+ method: "POST",
3283
+ operationId: OperationId.ToggleChecklistItem,
3284
+ path: "/api/v1/trips/{ref}/checklist/items/{itemId}/toggle",
3285
+ pathParams: { ref: tripRef, itemId },
3286
+ body,
3287
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3288
+ ...signal !== void 0 ? { signal } : {}
3289
+ });
3290
+ }
3291
+ },
3292
+ templates: {
3293
+ async list(options) {
3294
+ const { tripRef, locale, signal } = options;
3295
+ return client.execute({
3296
+ method: "GET",
3297
+ operationId: OperationId.ListChecklistTemplates,
3298
+ path: "/api/v1/trips/{ref}/checklist/templates",
3299
+ pathParams: { ref: tripRef },
3300
+ query: { locale },
3301
+ ...signal !== void 0 ? { signal } : {}
3302
+ });
3303
+ },
3304
+ async pull(options) {
3305
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3306
+ return client.execute({
3307
+ method: "POST",
3308
+ operationId: OperationId.PullChecklistTemplate,
3309
+ path: "/api/v1/trips/{ref}/checklist/pull-template",
3310
+ pathParams: { ref: tripRef },
3311
+ body,
3312
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3313
+ ...signal !== void 0 ? { signal } : {}
3314
+ });
3315
+ }
3316
+ }
3317
+ };
3318
+ }
3319
+
3320
+ // src/resources/closeout.ts
3321
+ function createCloseoutResource(client) {
3322
+ return {
3323
+ async get(options) {
3324
+ const { tripRef, since, signal } = options;
3325
+ return client.execute({
3326
+ method: "GET",
3327
+ operationId: OperationId.ReadCloseout,
3328
+ path: "/api/v1/trips/{ref}/closeout",
3329
+ pathParams: { ref: tripRef },
3330
+ query: { since },
3331
+ ...signal !== void 0 ? { signal } : {}
3332
+ });
3333
+ },
3334
+ async saveHandover(options) {
3335
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3336
+ return client.execute({
3337
+ method: "POST",
3338
+ operationId: OperationId.SaveCloseoutHandover,
3339
+ path: "/api/v1/trips/{ref}/closeout/handover",
3340
+ pathParams: { ref: tripRef },
3341
+ body,
3342
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3343
+ ...signal !== void 0 ? { signal } : {}
3344
+ });
3345
+ },
3346
+ async lock(options) {
3347
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3348
+ return client.execute({
3349
+ method: "POST",
3350
+ operationId: OperationId.LockCloseout,
3351
+ path: "/api/v1/trips/{ref}/closeout/lock",
3352
+ pathParams: { ref: tripRef },
3353
+ body,
3354
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3355
+ ...signal !== void 0 ? { signal } : {}
3356
+ });
3357
+ },
3358
+ async unlock(options) {
3359
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3360
+ return client.execute({
3361
+ method: "POST",
3362
+ operationId: OperationId.UnlockCloseout,
3363
+ path: "/api/v1/trips/{ref}/closeout/unlock",
3364
+ pathParams: { ref: tripRef },
3365
+ body,
3366
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3367
+ ...signal !== void 0 ? { signal } : {}
3368
+ });
3369
+ },
3370
+ async exportPdf(options) {
3371
+ const { tripRef, signal, ...body } = options;
3372
+ return client.executeBinary({
3373
+ method: "POST",
3374
+ operationId: OperationId.ExportCloseoutPack,
3375
+ path: "/api/v1/trips/{ref}/closeout/export-pdf",
3376
+ pathParams: { ref: tripRef },
3377
+ body,
3378
+ // The one place a non-JSON `Accept` is sent. `exportCloseoutPack`
3379
+ // declares no `Idempotency-Key` parameter
3380
+ // (`OPERATION_ACCEPTS_IDEMPOTENCY_KEY.exportCloseoutPack` is `false`),
3381
+ // and rightly — printing the same pack twice creates nothing — so no
3382
+ // key is offered here and the transport mints none.
3383
+ accept: "application/pdf",
3384
+ ...signal !== void 0 ? { signal } : {}
3385
+ });
3386
+ }
3387
+ };
3388
+ }
3389
+
3390
+ // src/resources/collections.ts
3391
+ function createCollectionsResource(client) {
3392
+ return {
3393
+ async list(options) {
3394
+ const { tripRef, travellerId, since, signal } = options;
3395
+ return client.execute({
3396
+ method: "GET",
3397
+ operationId: OperationId.ListCollections,
3398
+ path: "/api/v1/trips/{ref}/collections",
3399
+ pathParams: { ref: tripRef },
3400
+ query: { travellerId, since },
3401
+ ...signal !== void 0 ? { signal } : {}
3402
+ });
3403
+ },
3404
+ async eligible(options) {
3405
+ const { tripRef, signal } = options;
3406
+ return client.execute({
3407
+ method: "GET",
3408
+ operationId: OperationId.ListEligibleCollections,
3409
+ path: "/api/v1/trips/{ref}/collections/eligible",
3410
+ pathParams: { ref: tripRef },
3411
+ ...signal !== void 0 ? { signal } : {}
3412
+ });
3413
+ },
3414
+ async record(options) {
3415
+ const { tripRef, idempotencyKey, signal, collectedAt, ...rest } = options;
3416
+ const body = {
3417
+ ...rest,
3418
+ ...collectedAt !== void 0 ? { collectedAt: normalizeDateTimeInput(collectedAt, "collectedAt") } : {}
3419
+ };
3420
+ return client.execute({
3421
+ method: "POST",
3422
+ operationId: OperationId.RecordCollection,
3423
+ path: "/api/v1/trips/{ref}/collections",
3424
+ pathParams: { ref: tripRef },
3425
+ body,
3426
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3427
+ ...signal !== void 0 ? { signal } : {}
3428
+ });
3429
+ },
3430
+ async void(options) {
3431
+ const { tripRef, collectionId, version, signal, ...body } = options;
3432
+ return client.execute({
3433
+ method: "DELETE",
3434
+ operationId: OperationId.VoidCollection,
3435
+ path: "/api/v1/trips/{ref}/collections/{id}/void",
3436
+ pathParams: { ref: tripRef, id: collectionId },
3437
+ body,
3438
+ headers: { "If-Match": String(version) },
3439
+ ...signal !== void 0 ? { signal } : {}
3440
+ });
3441
+ }
3442
+ };
3443
+ }
3444
+
3445
+ // src/resources/expenses.ts
3446
+ function createExpensesResource(client) {
3447
+ return {
3448
+ async list(options) {
3449
+ const { tripRef, since, signal, ...filters } = options;
3450
+ return client.execute({
3451
+ method: "GET",
3452
+ operationId: OperationId.ListExpenses,
3453
+ path: "/api/v1/trips/{ref}/expenses",
3454
+ pathParams: { ref: tripRef },
3455
+ query: { ...filters, since },
3456
+ ...signal !== void 0 ? { signal } : {}
3457
+ });
3458
+ },
3459
+ async read(options) {
3460
+ const { tripRef, expenseId, signal } = options;
3461
+ return client.execute({
3462
+ method: "GET",
3463
+ operationId: OperationId.ReadExpense,
3464
+ path: "/api/v1/trips/{ref}/expenses/{id}",
3465
+ pathParams: { ref: tripRef, id: expenseId },
3466
+ ...signal !== void 0 ? { signal } : {}
3467
+ });
3468
+ },
3469
+ async log(options) {
3470
+ const { tripRef, idempotencyKey, signal, spentAt, ...rest } = options;
3471
+ const body = {
3472
+ ...rest,
3473
+ ...spentAt !== void 0 ? { spentAt: normalizeDateTimeInput(spentAt, "spentAt") } : {}
3474
+ };
3475
+ return client.execute({
3476
+ method: "POST",
3477
+ operationId: OperationId.LogExpense,
3478
+ path: "/api/v1/trips/{ref}/expenses",
3479
+ pathParams: { ref: tripRef },
3480
+ body,
3481
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3482
+ ...signal !== void 0 ? { signal } : {}
3483
+ });
3484
+ },
3485
+ async linkReceipt(options) {
3486
+ const { tripRef, expenseId, idempotencyKey, signal, ...body } = options;
3487
+ return client.execute({
3488
+ method: "PATCH",
3489
+ operationId: OperationId.LinkExpenseReceipt,
3490
+ path: "/api/v1/trips/{ref}/expenses/{id}/receipt",
3491
+ pathParams: { ref: tripRef, id: expenseId },
3492
+ body,
3493
+ idempotencyKey,
3494
+ ...signal !== void 0 ? { signal } : {}
3495
+ });
3496
+ },
3497
+ async void(options) {
3498
+ const { tripRef, expenseId, version, signal, ...body } = options;
3499
+ return client.execute({
3500
+ method: "DELETE",
3501
+ operationId: OperationId.VoidExpense,
3502
+ path: "/api/v1/trips/{ref}/expenses/{id}/void",
3503
+ pathParams: { ref: tripRef, id: expenseId },
3504
+ body,
3505
+ headers: { "If-Match": String(version) },
3506
+ ...signal !== void 0 ? { signal } : {}
3507
+ });
3508
+ },
3509
+ claims: {
3510
+ async submit(options) {
3511
+ const { tripRef, expenseId, idempotencyKey, signal } = options;
3512
+ return client.execute({
3513
+ method: "POST",
3514
+ operationId: OperationId.SubmitExpenseClaim,
3515
+ path: "/api/v1/trips/{ref}/expenses/{id}/claim",
3516
+ pathParams: { ref: tripRef, id: expenseId },
3517
+ body: {},
3518
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3519
+ ...signal !== void 0 ? { signal } : {}
3520
+ });
3521
+ },
3522
+ async withdraw(options) {
3523
+ const { tripRef, expenseId, version, signal } = options;
3524
+ return client.execute({
3525
+ method: "DELETE",
3526
+ operationId: OperationId.WithdrawExpenseClaim,
3527
+ path: "/api/v1/trips/{ref}/expenses/{id}/claim/withdraw",
3528
+ pathParams: { ref: tripRef, id: expenseId },
3529
+ body: {},
3530
+ headers: { "If-Match": String(version) },
3531
+ ...signal !== void 0 ? { signal } : {}
3532
+ });
3533
+ },
3534
+ async ingest(options) {
3535
+ const { tripRef, expenseId, idempotencyKey, signal, decisionAt, ...rest } = options;
3536
+ const body = {
3537
+ ...rest,
3538
+ decisionAt: normalizeDateTimeInput(decisionAt, "decisionAt")
3539
+ };
3540
+ return client.execute({
3541
+ method: "POST",
3542
+ operationId: OperationId.ClaimStatusIngest,
3543
+ path: "/api/v1/trips/{ref}/expenses/{id}/claim-status",
3544
+ pathParams: { ref: tripRef, id: expenseId },
3545
+ body,
3546
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3547
+ ...signal !== void 0 ? { signal } : {}
3548
+ });
3549
+ }
3550
+ }
3551
+ };
3552
+ }
3553
+
3554
+ // src/resources/files.ts
3555
+ function createFilesResource(client) {
3556
+ return {
3557
+ async request(options) {
3558
+ const { idempotencyKey, signal, ...body } = options;
3559
+ return client.execute({
3560
+ method: "POST",
3561
+ operationId: OperationId.RequestFileUpload,
3562
+ path: "/api/v1/files",
3563
+ body,
3564
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3565
+ ...signal !== void 0 ? { signal } : {}
3566
+ });
3567
+ },
3568
+ async meta(options) {
3569
+ const { fileId, signal } = options;
3570
+ return client.execute({
3571
+ method: "GET",
3572
+ operationId: OperationId.ReadFile,
3573
+ path: "/api/v1/files/{id}",
3574
+ pathParams: { id: fileId },
3575
+ ...signal !== void 0 ? { signal } : {}
3576
+ });
3577
+ },
3578
+ async confirm(options) {
3579
+ const { fileId, idempotencyKey, signal } = options;
3580
+ return client.execute({
3581
+ method: "POST",
3582
+ operationId: OperationId.ConfirmFileUpload,
3583
+ path: "/api/v1/files/{id}/confirm",
3584
+ pathParams: { id: fileId },
3585
+ body: {},
3586
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3587
+ ...signal !== void 0 ? { signal } : {}
3588
+ });
3589
+ },
3590
+ async url(options) {
3591
+ const { fileId, signal } = options;
3592
+ return client.execute({
3593
+ method: "GET",
3594
+ operationId: OperationId.ReadFileUrl,
3595
+ path: "/api/v1/files/{id}/url",
3596
+ pathParams: { id: fileId },
3597
+ ...signal !== void 0 ? { signal } : {}
3598
+ });
3599
+ }
3600
+ };
3601
+ }
3602
+
3603
+ // src/resources/float.ts
3604
+ function createFloatResource(client) {
3605
+ return {
3606
+ async readSummary(options) {
3607
+ const { tripRef, since, signal } = options;
3608
+ return client.execute({
3609
+ method: "GET",
3610
+ operationId: OperationId.ReadFloatSummary,
3611
+ path: "/api/v1/trips/{ref}/float",
3612
+ pathParams: { ref: tripRef },
3613
+ query: { since },
3614
+ ...signal !== void 0 ? { signal } : {}
3615
+ });
3616
+ },
3617
+ async readLedger(options) {
3618
+ const { tripRef, managerId, signal } = options;
3619
+ return client.execute({
3620
+ method: "GET",
3621
+ operationId: OperationId.ReadFloatLedger,
3622
+ path: "/api/v1/trips/{ref}/float/{managerId}/ledger",
3623
+ pathParams: { ref: tripRef, managerId },
3624
+ ...signal !== void 0 ? { signal } : {}
3625
+ });
3626
+ },
3627
+ async issue(options) {
3628
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3629
+ return client.execute({
3630
+ method: "POST",
3631
+ operationId: OperationId.IssueFloat,
3632
+ path: "/api/v1/trips/{ref}/float/issue",
3633
+ pathParams: { ref: tripRef },
3634
+ body,
3635
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3636
+ ...signal !== void 0 ? { signal } : {}
3637
+ });
3638
+ },
3639
+ async return(options) {
3640
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3641
+ return client.execute({
3642
+ method: "POST",
3643
+ operationId: OperationId.ReturnFloat,
3644
+ path: "/api/v1/trips/{ref}/float/return",
3645
+ pathParams: { ref: tripRef },
3646
+ body,
3647
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3648
+ ...signal !== void 0 ? { signal } : {}
3649
+ });
3650
+ },
3651
+ async adjust(options) {
3652
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3653
+ return client.execute({
3654
+ method: "POST",
3655
+ operationId: OperationId.AdjustFloat,
3656
+ path: "/api/v1/trips/{ref}/float/adjust",
3657
+ pathParams: { ref: tripRef },
3658
+ body,
3659
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3660
+ ...signal !== void 0 ? { signal } : {}
3661
+ });
3662
+ }
3663
+ };
3664
+ }
3665
+
3666
+ // src/resources/itinerary.ts
3667
+ function createItineraryResource(client) {
3668
+ return {
3669
+ async read(options) {
3670
+ const { tripRef, dayIndex, since, signal } = options;
3671
+ return client.execute({
3672
+ method: "GET",
3673
+ operationId: OperationId.ReadItinerary,
3674
+ path: "/api/v1/trips/{ref}/itinerary",
3675
+ pathParams: { ref: tripRef },
3676
+ query: { dayIndex, since },
3677
+ ...signal !== void 0 ? { signal } : {}
3678
+ });
3679
+ },
3680
+ items: {
3681
+ async add(options) {
3682
+ const { tripRef, idempotencyKey, signal, isoDate, startTime, endTime, ...rest } = options;
3683
+ const body = {
3684
+ ...rest,
3685
+ isoDate: normalizeDateTimeInput(isoDate, "isoDate"),
3686
+ ...startTime !== void 0 ? { startTime: normalizeNullableDateTimeInput(startTime, "startTime") } : {},
3687
+ ...endTime !== void 0 ? { endTime: normalizeNullableDateTimeInput(endTime, "endTime") } : {}
3688
+ };
3689
+ return client.execute({
3690
+ method: "POST",
3691
+ operationId: OperationId.AddItineraryItem,
3692
+ path: "/api/v1/trips/{ref}/itinerary/items",
3693
+ pathParams: { ref: tripRef },
3694
+ body,
3695
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3696
+ ...signal !== void 0 ? { signal } : {}
3697
+ });
3698
+ },
3699
+ async patch(options) {
3700
+ const { tripRef, itemId, version, signal, startTime, endTime, ...rest } = options;
3701
+ const body = {
3702
+ ...rest,
3703
+ ...startTime !== void 0 ? { startTime: normalizeNullableDateTimeInput(startTime, "startTime") } : {},
3704
+ ...endTime !== void 0 ? { endTime: normalizeNullableDateTimeInput(endTime, "endTime") } : {}
3705
+ };
3706
+ return client.execute({
3707
+ method: "PATCH",
3708
+ operationId: OperationId.PatchItineraryItem,
3709
+ path: "/api/v1/trips/{ref}/itinerary/items/{itemId}",
3710
+ pathParams: { ref: tripRef, itemId },
3711
+ body,
3712
+ headers: { "If-Match": String(version) },
3713
+ ...signal !== void 0 ? { signal } : {}
3714
+ });
3715
+ },
3716
+ async remove(options) {
3717
+ const { tripRef, itemId, version, signal } = options;
3718
+ return client.execute({
3719
+ method: "DELETE",
3720
+ operationId: OperationId.DeleteItineraryItem,
3721
+ path: "/api/v1/trips/{ref}/itinerary/items/{itemId}",
3722
+ pathParams: { ref: tripRef, itemId },
3723
+ headers: { "If-Match": String(version) },
3724
+ ...signal !== void 0 ? { signal } : {}
3725
+ });
3726
+ },
3727
+ async reorder(options) {
3728
+ const { tripRef, itemId, idempotencyKey, signal, ...body } = options;
3729
+ return client.execute({
3730
+ method: "POST",
3731
+ operationId: OperationId.ReorderItineraryItem,
3732
+ path: "/api/v1/trips/{ref}/itinerary/items/{itemId}/reorder",
3733
+ pathParams: { ref: tripRef, itemId },
3734
+ body,
3735
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3736
+ ...signal !== void 0 ? { signal } : {}
3737
+ });
3738
+ }
3739
+ },
3740
+ days: {
3741
+ async patch(options) {
3742
+ const { tripRef, dayIndex, version, signal, ...body } = options;
3743
+ return client.execute({
3744
+ method: "PATCH",
3745
+ operationId: OperationId.PatchItineraryDay,
3746
+ path: "/api/v1/trips/{ref}/itinerary/days/{dayIndex}",
3747
+ pathParams: { ref: tripRef, dayIndex },
3748
+ body,
3749
+ headers: { "If-Match": String(version) },
3750
+ ...signal !== void 0 ? { signal } : {}
3751
+ });
3752
+ }
3753
+ },
3754
+ changeLog: {
3755
+ async list(options) {
3756
+ const { tripRef, since, signal } = options;
3757
+ return client.execute({
3758
+ method: "GET",
3759
+ operationId: OperationId.ReadItineraryChangeLog,
3760
+ path: "/api/v1/trips/{ref}/itinerary/change-log",
3761
+ pathParams: { ref: tripRef },
3762
+ query: { since },
3763
+ ...signal !== void 0 ? { signal } : {}
3764
+ });
3765
+ }
3766
+ }
3767
+ };
3768
+ }
3769
+
3770
+ // src/resources/journey.ts
3771
+ var DEFAULT_WAIT_UNTIL_READY_TIMEOUT_MS = 6e4;
3772
+ var DEFAULT_WAIT_UNTIL_READY_POLL_INTERVAL_MS = 1e3;
3773
+ function createJourneyResource(client) {
3774
+ const resource = {
3775
+ async get(options) {
3776
+ const { tripRef, signal } = options;
3777
+ return client.execute({
3778
+ method: "GET",
3779
+ operationId: OperationId.ReadJourney,
3780
+ path: "/api/v1/trips/{ref}/journey",
3781
+ pathParams: { ref: tripRef },
3782
+ ...signal !== void 0 ? { signal } : {}
3783
+ });
3784
+ },
3785
+ async capabilities(options) {
3786
+ const { tripRef, signal } = options;
3787
+ return client.execute({
3788
+ method: "GET",
3789
+ operationId: OperationId.ReadJourneyCapabilities,
3790
+ path: "/api/v1/trips/{ref}/journey/capabilities",
3791
+ pathParams: { ref: tripRef },
3792
+ ...signal !== void 0 ? { signal } : {}
3793
+ });
3794
+ },
3795
+ async rebuild(options) {
3796
+ const { tripRef, idempotencyKey, signal } = options;
3797
+ return client.execute({
3798
+ method: "POST",
3799
+ operationId: OperationId.RebuildJourney,
3800
+ path: "/api/v1/trips/{ref}/journey/rebuild",
3801
+ pathParams: { ref: tripRef },
3802
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3803
+ ...signal !== void 0 ? { signal } : {}
3804
+ });
3805
+ },
3806
+ async runStep(options) {
3807
+ const { tripRef, stepId, idempotencyKey, signal } = options;
3808
+ return client.execute({
3809
+ method: "POST",
3810
+ operationId: OperationId.RunJourneyStep,
3811
+ path: "/api/v1/trips/{ref}/journey/steps/{stepId}/run",
3812
+ pathParams: { ref: tripRef, stepId },
3813
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3814
+ ...signal !== void 0 ? { signal } : {}
3815
+ });
3816
+ },
3817
+ async waitUntilReady(options) {
3818
+ const {
3819
+ tripRef,
3820
+ timeoutMs = DEFAULT_WAIT_UNTIL_READY_TIMEOUT_MS,
3821
+ pollIntervalMs = DEFAULT_WAIT_UNTIL_READY_POLL_INTERVAL_MS,
3822
+ signal
3823
+ } = options;
3824
+ const deadlineAt = Date.now() + timeoutMs;
3825
+ for (; ; ) {
3826
+ try {
3827
+ return await resource.get({ tripRef, ...signal !== void 0 ? { signal } : {} });
3828
+ } catch (error) {
3829
+ if (!(error instanceof KaafilNotFoundError)) {
3830
+ throw error;
3831
+ }
3832
+ const remainingMs = deadlineAt - Date.now();
3833
+ if (remainingMs <= 0) {
3834
+ throw new KaafilTimeoutError(
3835
+ `journey.waitUntilReady timed out after ${String(timeoutMs)}ms waiting for trip "${tripRef}" to become ready. The most likely cause is that the background worker that consumes the build queue is not running against this engine.`,
3836
+ { cause: error }
3837
+ );
3838
+ }
3839
+ try {
3840
+ await delayWithAbort(Math.min(pollIntervalMs, remainingMs), signal);
3841
+ } catch (sleepError) {
3842
+ throw new KaafilAbortError("Request aborted", { cause: sleepError });
3843
+ }
3844
+ }
3845
+ }
3846
+ },
3847
+ triggers: {
3848
+ async list(options) {
3849
+ const { agencyRef, signal } = options;
3850
+ return client.execute({
3851
+ method: "GET",
3852
+ operationId: OperationId.ListJourneyTriggers,
3853
+ path: "/api/v1/agencies/{ref}/journey-triggers",
3854
+ pathParams: { ref: agencyRef },
3855
+ ...signal !== void 0 ? { signal } : {}
3856
+ });
3857
+ },
3858
+ async patch(options) {
3859
+ const { agencyRef, key, version, idempotencyKey, signal, ...body } = options;
3860
+ return client.execute({
3861
+ method: "PATCH",
3862
+ operationId: OperationId.PatchJourneyTrigger,
3863
+ path: "/api/v1/agencies/{ref}/journey-triggers/{key}",
3864
+ pathParams: { ref: agencyRef, key },
3865
+ body,
3866
+ headers: { "If-Match": String(version) },
3867
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3868
+ ...signal !== void 0 ? { signal } : {}
3869
+ });
3870
+ }
3871
+ }
3872
+ };
3873
+ return resource;
3874
+ }
3875
+
3876
+ // src/resources/notifications.ts
3877
+ function createNotificationsResource(client) {
3878
+ return {
3879
+ async list(options = {}) {
3880
+ const { since, signal } = options;
3881
+ return client.execute({
3882
+ method: "GET",
3883
+ operationId: OperationId.ListManagerNotifications,
3884
+ path: "/api/v1/managers/me/notifications",
3885
+ ...since !== void 0 ? { query: { since } } : {},
3886
+ ...signal !== void 0 ? { signal } : {}
3887
+ });
3888
+ }
3889
+ };
3890
+ }
3891
+
3892
+ // src/resources/pickups.ts
3893
+ function createPickupsResource(client) {
3894
+ return {
3895
+ async list(options) {
3896
+ const { tripRef, kind, since, signal } = options;
3897
+ return client.execute({
3898
+ method: "GET",
3899
+ operationId: OperationId.ListPickupStops,
3900
+ path: "/api/v1/trips/{ref}/pickups",
3901
+ pathParams: { ref: tripRef },
3902
+ query: { kind, since },
3903
+ ...signal !== void 0 ? { signal } : {}
3904
+ });
3905
+ },
3906
+ async create(options) {
3907
+ const { tripRef, idempotencyKey, signal, scheduledTime, ...rest } = options;
3908
+ const body = {
3909
+ ...rest,
3910
+ scheduledTime: normalizeDateTimeInput(scheduledTime, "scheduledTime")
3911
+ };
3912
+ return client.execute({
3913
+ method: "POST",
3914
+ operationId: OperationId.CreatePickupStop,
3915
+ path: "/api/v1/trips/{ref}/pickups",
3916
+ pathParams: { ref: tripRef },
3917
+ body,
3918
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3919
+ ...signal !== void 0 ? { signal } : {}
3920
+ });
3921
+ },
3922
+ async patch(options) {
3923
+ const { tripRef, pointId, version, signal, scheduledTime, ...rest } = options;
3924
+ const body = {
3925
+ ...rest,
3926
+ ...scheduledTime !== void 0 ? { scheduledTime: normalizeDateTimeInput(scheduledTime, "scheduledTime") } : {}
3927
+ };
3928
+ return client.execute({
3929
+ method: "PATCH",
3930
+ operationId: OperationId.PatchPickupStop,
3931
+ path: "/api/v1/trips/{ref}/pickups/{pointId}",
3932
+ pathParams: { ref: tripRef, pointId },
3933
+ body,
3934
+ headers: { "If-Match": String(version) },
3935
+ ...signal !== void 0 ? { signal } : {}
3936
+ });
3937
+ },
3938
+ async remove(options) {
3939
+ const { tripRef, pointId, version, force, signal } = options;
3940
+ return client.execute({
3941
+ method: "DELETE",
3942
+ operationId: OperationId.DeletePickupStop,
3943
+ path: "/api/v1/trips/{ref}/pickups/{pointId}",
3944
+ pathParams: { ref: tripRef, pointId },
3945
+ query: { force },
3946
+ headers: { "If-Match": String(version) },
3947
+ ...signal !== void 0 ? { signal } : {}
3948
+ });
3949
+ },
3950
+ async reorder(options) {
3951
+ const { tripRef, idempotencyKey, signal, ...body } = options;
3952
+ return client.execute({
3953
+ method: "POST",
3954
+ operationId: OperationId.ReorderPickupStops,
3955
+ path: "/api/v1/trips/{ref}/pickups/reorder",
3956
+ pathParams: { ref: tripRef },
3957
+ body,
3958
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3959
+ ...signal !== void 0 ? { signal } : {}
3960
+ });
3961
+ },
3962
+ async assign(options) {
3963
+ const { tripRef, pointId, idempotencyKey, signal, ...body } = options;
3964
+ return client.execute({
3965
+ method: "POST",
3966
+ operationId: OperationId.AssignPickupTraveller,
3967
+ path: "/api/v1/trips/{ref}/pickups/{pointId}/assign",
3968
+ pathParams: { ref: tripRef, pointId },
3969
+ body,
3970
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3971
+ ...signal !== void 0 ? { signal } : {}
3972
+ });
3973
+ },
3974
+ async board(options) {
3975
+ const { tripRef, pointId, idempotencyKey, signal, ...body } = options;
3976
+ return client.execute({
3977
+ method: "POST",
3978
+ operationId: OperationId.BoardPickupTraveller,
3979
+ path: "/api/v1/trips/{ref}/pickups/{pointId}/board",
3980
+ pathParams: { ref: tripRef, pointId },
3981
+ body,
3982
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3983
+ ...signal !== void 0 ? { signal } : {}
3984
+ });
3985
+ },
3986
+ async close(options) {
3987
+ const { tripRef, pointId, idempotencyKey, signal, ...body } = options;
3988
+ return client.execute({
3989
+ method: "POST",
3990
+ operationId: OperationId.ClosePickupStop,
3991
+ path: "/api/v1/trips/{ref}/pickups/{pointId}/close",
3992
+ pathParams: { ref: tripRef, pointId },
3993
+ body,
3994
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
3995
+ ...signal !== void 0 ? { signal } : {}
3996
+ });
3997
+ },
3998
+ async reopen(options) {
3999
+ const { tripRef, pointId, idempotencyKey, signal } = options;
4000
+ return client.execute({
4001
+ method: "POST",
4002
+ operationId: OperationId.ReopenPickupStop,
4003
+ path: "/api/v1/trips/{ref}/pickups/{pointId}/reopen",
4004
+ pathParams: { ref: tripRef, pointId },
4005
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4006
+ ...signal !== void 0 ? { signal } : {}
4007
+ });
4008
+ },
4009
+ async manifestByPickup(options) {
4010
+ const { tripRef, kind, signal } = options;
4011
+ return client.execute({
4012
+ method: "GET",
4013
+ operationId: OperationId.ReadManifestByPickup,
4014
+ path: "/api/v1/trips/{ref}/manifest-by-pickup",
4015
+ pathParams: { ref: tripRef },
4016
+ query: { kind },
4017
+ ...signal !== void 0 ? { signal } : {}
4018
+ });
4019
+ }
4020
+ };
4021
+ }
4022
+
4023
+ // src/resources/rooming.ts
4024
+ function createRoomingResource(client) {
4025
+ return {
4026
+ async read(options) {
4027
+ const { tripRef, stayWindowId, since, signal } = options;
4028
+ return client.execute({
4029
+ method: "GET",
4030
+ operationId: OperationId.ReadRoomingBoard,
4031
+ path: "/api/v1/trips/{ref}/rooming",
4032
+ pathParams: { ref: tripRef },
4033
+ query: { stayWindowId, since },
4034
+ ...signal !== void 0 ? { signal } : {}
4035
+ });
4036
+ },
4037
+ async assign(options) {
4038
+ const { tripRef, idempotencyKey, signal, ...body } = options;
4039
+ return client.execute({
4040
+ method: "POST",
4041
+ operationId: OperationId.AssignRoomingBed,
4042
+ path: "/api/v1/trips/{ref}/rooming/assign",
4043
+ pathParams: { ref: tripRef },
4044
+ body,
4045
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4046
+ ...signal !== void 0 ? { signal } : {}
4047
+ });
4048
+ },
4049
+ async autoAssign(options) {
4050
+ const { tripRef, idempotencyKey, signal, ...body } = options;
4051
+ return client.execute({
4052
+ method: "POST",
4053
+ operationId: OperationId.AutoAssignRooming,
4054
+ path: "/api/v1/trips/{ref}/rooming/auto-assign",
4055
+ pathParams: { ref: tripRef },
4056
+ body,
4057
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4058
+ ...signal !== void 0 ? { signal } : {}
4059
+ });
4060
+ },
4061
+ stayWindows: {
4062
+ async list(options) {
4063
+ const { tripRef, since, signal } = options;
4064
+ return client.execute({
4065
+ method: "GET",
4066
+ operationId: OperationId.ListRoomingStayWindows,
4067
+ path: "/api/v1/trips/{ref}/rooming/stay-windows",
4068
+ pathParams: { ref: tripRef },
4069
+ query: { since },
4070
+ ...signal !== void 0 ? { signal } : {}
4071
+ });
4072
+ },
4073
+ async create(options) {
4074
+ const { tripRef, idempotencyKey, signal, startDate, endDate, ...rest } = options;
4075
+ const body = {
4076
+ ...rest,
4077
+ startDate: normalizeDateTimeInput(startDate, "startDate"),
4078
+ endDate: normalizeDateTimeInput(endDate, "endDate")
4079
+ };
4080
+ return client.execute({
4081
+ method: "POST",
4082
+ operationId: OperationId.CreateRoomingStayWindow,
4083
+ path: "/api/v1/trips/{ref}/rooming/stay-windows",
4084
+ pathParams: { ref: tripRef },
4085
+ body,
4086
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4087
+ ...signal !== void 0 ? { signal } : {}
4088
+ });
4089
+ },
4090
+ async patch(options) {
4091
+ const { tripRef, windowId, version, signal, startDate, endDate, ...rest } = options;
4092
+ const body = {
4093
+ ...rest,
4094
+ ...startDate !== void 0 ? { startDate: normalizeDateTimeInput(startDate, "startDate") } : {},
4095
+ ...endDate !== void 0 ? { endDate: normalizeDateTimeInput(endDate, "endDate") } : {}
4096
+ };
4097
+ return client.execute({
4098
+ method: "PATCH",
4099
+ operationId: OperationId.PatchRoomingStayWindow,
4100
+ path: "/api/v1/trips/{ref}/rooming/stay-windows/{windowId}",
4101
+ pathParams: { ref: tripRef, windowId },
4102
+ body,
4103
+ headers: { "If-Match": String(version) },
4104
+ ...signal !== void 0 ? { signal } : {}
4105
+ });
4106
+ },
4107
+ async remove(options) {
4108
+ const { tripRef, windowId, version, force, signal } = options;
4109
+ return client.execute({
4110
+ method: "DELETE",
4111
+ operationId: OperationId.DeleteRoomingStayWindow,
4112
+ path: "/api/v1/trips/{ref}/rooming/stay-windows/{windowId}",
4113
+ pathParams: { ref: tripRef, windowId },
4114
+ query: { force },
4115
+ headers: { "If-Match": String(version) },
4116
+ ...signal !== void 0 ? { signal } : {}
4117
+ });
4118
+ }
4119
+ },
4120
+ rooms: {
4121
+ async create(options) {
4122
+ const { tripRef, idempotencyKey, signal, ...body } = options;
4123
+ return client.execute({
4124
+ method: "POST",
4125
+ operationId: OperationId.CreateRoomingRoom,
4126
+ path: "/api/v1/trips/{ref}/rooming/rooms",
4127
+ pathParams: { ref: tripRef },
4128
+ body,
4129
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4130
+ ...signal !== void 0 ? { signal } : {}
4131
+ });
4132
+ },
4133
+ async patch(options) {
4134
+ const { tripRef, roomId, version, signal, ...body } = options;
4135
+ return client.execute({
4136
+ method: "PATCH",
4137
+ operationId: OperationId.PatchRoomingRoom,
4138
+ path: "/api/v1/trips/{ref}/rooming/rooms/{roomId}",
4139
+ pathParams: { ref: tripRef, roomId },
4140
+ body,
4141
+ headers: { "If-Match": String(version) },
4142
+ ...signal !== void 0 ? { signal } : {}
4143
+ });
4144
+ },
4145
+ async remove(options) {
4146
+ const { tripRef, roomId, version, force, signal } = options;
4147
+ return client.execute({
4148
+ method: "DELETE",
4149
+ operationId: OperationId.DeleteRoomingRoom,
4150
+ path: "/api/v1/trips/{ref}/rooming/rooms/{roomId}",
4151
+ pathParams: { ref: tripRef, roomId },
4152
+ query: { force },
4153
+ headers: { "If-Match": String(version) },
4154
+ ...signal !== void 0 ? { signal } : {}
4155
+ });
4156
+ }
4157
+ }
4158
+ };
4159
+ }
4160
+
4161
+ // src/resources/seating.ts
4162
+ function createSeatingResource(client) {
4163
+ return {
4164
+ async read(options) {
4165
+ const { tripRef, since, signal } = options;
4166
+ return client.execute({
4167
+ method: "GET",
4168
+ operationId: OperationId.ReadSeatingBoard,
4169
+ path: "/api/v1/trips/{ref}/seating",
4170
+ pathParams: { ref: tripRef },
4171
+ query: { since },
4172
+ ...signal !== void 0 ? { signal } : {}
4173
+ });
4174
+ },
4175
+ async assign(options) {
4176
+ const { tripRef, idempotencyKey, signal, ...body } = options;
4177
+ return client.execute({
4178
+ method: "POST",
4179
+ operationId: OperationId.AssignSeating,
4180
+ path: "/api/v1/trips/{ref}/seating/assign",
4181
+ pathParams: { ref: tripRef },
4182
+ body,
4183
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4184
+ ...signal !== void 0 ? { signal } : {}
4185
+ });
4186
+ },
4187
+ async autoAssign(options) {
4188
+ const { tripRef, idempotencyKey, signal, ...body } = options;
4189
+ return client.execute({
4190
+ method: "POST",
4191
+ operationId: OperationId.AutoAssignSeating,
4192
+ path: "/api/v1/trips/{ref}/seating/auto-assign",
4193
+ pathParams: { ref: tripRef },
4194
+ body,
4195
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4196
+ ...signal !== void 0 ? { signal } : {}
4197
+ });
4198
+ },
4199
+ vehicles: {
4200
+ async create(options) {
4201
+ const { tripRef, idempotencyKey, signal, ...body } = options;
4202
+ return client.execute({
4203
+ method: "POST",
4204
+ operationId: OperationId.CreateSeatingVehicle,
4205
+ path: "/api/v1/trips/{ref}/seating/vehicles",
4206
+ pathParams: { ref: tripRef },
4207
+ body,
4208
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4209
+ ...signal !== void 0 ? { signal } : {}
4210
+ });
4211
+ },
4212
+ async patch(options) {
4213
+ const { tripRef, vehicleId, version, signal, ...body } = options;
4214
+ return client.execute({
4215
+ method: "PATCH",
4216
+ operationId: OperationId.PatchSeatingVehicle,
4217
+ path: "/api/v1/trips/{ref}/seating/vehicles/{vehicleId}",
4218
+ pathParams: { ref: tripRef, vehicleId },
4219
+ body,
4220
+ headers: { "If-Match": String(version) },
4221
+ ...signal !== void 0 ? { signal } : {}
4222
+ });
4223
+ },
4224
+ async remove(options) {
4225
+ const { tripRef, vehicleId, version, signal } = options;
4226
+ return client.execute({
4227
+ method: "DELETE",
4228
+ operationId: OperationId.DeleteSeatingVehicle,
4229
+ path: "/api/v1/trips/{ref}/seating/vehicles/{vehicleId}",
4230
+ pathParams: { ref: tripRef, vehicleId },
4231
+ headers: { "If-Match": String(version) },
4232
+ ...signal !== void 0 ? { signal } : {}
4233
+ });
4234
+ },
4235
+ manager: {
4236
+ async link(options) {
4237
+ const { tripRef, vehicleId, idempotencyKey, signal, ...body } = options;
4238
+ return client.execute({
4239
+ method: "POST",
4240
+ operationId: OperationId.LinkSeatingManager,
4241
+ path: "/api/v1/trips/{ref}/seating/vehicles/{vehicleId}/manager",
4242
+ pathParams: { ref: tripRef, vehicleId },
4243
+ body,
4244
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4245
+ ...signal !== void 0 ? { signal } : {}
4246
+ });
4247
+ },
4248
+ async unlink(options) {
4249
+ const { tripRef, vehicleId, version, signal } = options;
4250
+ return client.execute({
4251
+ method: "DELETE",
4252
+ operationId: OperationId.UnlinkSeatingManager,
4253
+ path: "/api/v1/trips/{ref}/seating/vehicles/{vehicleId}/manager",
4254
+ pathParams: { ref: tripRef, vehicleId },
4255
+ headers: { "If-Match": String(version) },
4256
+ ...signal !== void 0 ? { signal } : {}
4257
+ });
4258
+ }
4259
+ }
4260
+ }
4261
+ };
4262
+ }
4263
+
4264
+ // src/resources/share.ts
4265
+ function createShareResource(client) {
4266
+ return {
4267
+ async snapshot(options) {
4268
+ const { token, signal } = options;
4269
+ return client.execute({
4270
+ method: "GET",
4271
+ operationId: OperationId.GetShareSnapshot,
4272
+ path: "/api/v1/share/{token}",
4273
+ pathParams: { token },
4274
+ ...signal !== void 0 ? { signal } : {}
4275
+ });
4276
+ },
4277
+ async manifest(options) {
4278
+ const { token, signal } = options;
4279
+ return client.execute({
4280
+ method: "GET",
4281
+ operationId: OperationId.GetShareManifest,
4282
+ path: "/api/v1/share/{token}/manifest",
4283
+ pathParams: { token },
4284
+ ...signal !== void 0 ? { signal } : {}
4285
+ });
4286
+ },
4287
+ forms: {
4288
+ async list(options) {
4289
+ const { token, signal } = options;
4290
+ return client.execute({
4291
+ method: "GET",
4292
+ operationId: OperationId.ShareListForms,
4293
+ path: "/api/v1/share/{token}/forms",
4294
+ pathParams: { token },
4295
+ ...signal !== void 0 ? { signal } : {}
4296
+ });
1647
4297
  },
1648
4298
  async render(options) {
1649
4299
  const { token, formId, travellerRef, signal } = options;
@@ -1686,6 +4336,64 @@ function createShareResource(client) {
1686
4336
  };
1687
4337
  }
1688
4338
 
4339
+ // src/resources/treks.ts
4340
+ var ACTIVE_TREK_REF = "active";
4341
+ function createTreksResource(client) {
4342
+ return {
4343
+ async board(options) {
4344
+ const { trekRef, signal } = options;
4345
+ return client.execute({
4346
+ method: "GET",
4347
+ operationId: OperationId.ReadTrekBoard,
4348
+ path: "/api/v1/treks/{trekRef}/board",
4349
+ pathParams: { trekRef },
4350
+ ...signal !== void 0 ? { signal } : {}
4351
+ });
4352
+ },
4353
+ async postpone(options) {
4354
+ const { trekRef, idempotencyKey, signal, newStartDate, newEndDate, ...rest } = options;
4355
+ const body = {
4356
+ ...rest,
4357
+ newStartDate: normalizeDateTimeInput(newStartDate, "newStartDate"),
4358
+ newEndDate: normalizeDateTimeInput(newEndDate, "newEndDate")
4359
+ };
4360
+ return client.execute({
4361
+ method: "POST",
4362
+ operationId: OperationId.PostponeTrek,
4363
+ path: "/api/v1/treks/{trekRef}/postpone",
4364
+ pathParams: { trekRef },
4365
+ body,
4366
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4367
+ ...signal !== void 0 ? { signal } : {}
4368
+ });
4369
+ },
4370
+ walkIns: {
4371
+ async meta(options) {
4372
+ const { trekRef, signal } = options;
4373
+ return client.execute({
4374
+ method: "GET",
4375
+ operationId: OperationId.ReadTrekWalkInMeta,
4376
+ path: "/api/v1/treks/{trekRef}/walk-ins/meta",
4377
+ pathParams: { trekRef },
4378
+ ...signal !== void 0 ? { signal } : {}
4379
+ });
4380
+ },
4381
+ async create(options) {
4382
+ const { trekRef, idempotencyKey, signal, ...body } = options;
4383
+ return client.execute({
4384
+ method: "POST",
4385
+ operationId: OperationId.CreateTrekWalkIn,
4386
+ path: "/api/v1/treks/{trekRef}/walk-ins",
4387
+ pathParams: { trekRef },
4388
+ body,
4389
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
4390
+ ...signal !== void 0 ? { signal } : {}
4391
+ });
4392
+ }
4393
+ }
4394
+ };
4395
+ }
4396
+
1689
4397
  // src/resources/vendors.ts
1690
4398
  function createVendorsResource(client) {
1691
4399
  return {
@@ -1703,26 +4411,116 @@ function createVendorsResource(client) {
1703
4411
  }
1704
4412
 
1705
4413
  // src/generated/enums.ts
4414
+ var BoardStatus = {
4415
+ Boarded: "BOARDED",
4416
+ NoShow: "NO_SHOW"
4417
+ };
1706
4418
  var BookingStatus = {
1707
4419
  Confirmed: "CONFIRMED",
1708
4420
  Tentative: "TENTATIVE",
1709
4421
  Cancelled: "CANCELLED"
1710
4422
  };
4423
+ var ChecklistAudience = {
4424
+ Internal: "INTERNAL",
4425
+ External: "EXTERNAL"
4426
+ };
4427
+ var ChecklistGate = {
4428
+ None: "NONE",
4429
+ PreToActive: "PRE_TO_ACTIVE",
4430
+ ActiveToClosedOut: "ACTIVE_TO_CLOSED_OUT"
4431
+ };
4432
+ var ChecklistItemStatus = {
4433
+ Open: "OPEN",
4434
+ Complete: "COMPLETE"
4435
+ };
4436
+ var ChecklistPhase = {
4437
+ PreDeparture: "PRE_DEPARTURE",
4438
+ InTrip: "IN_TRIP",
4439
+ PostTrip: "POST_TRIP"
4440
+ };
4441
+ var ChecklistPullTemplateMode = {
4442
+ Append: "append",
4443
+ Replace: "replace"
4444
+ };
1711
4445
  var ClaimStatusIngest = {
1712
4446
  Approved: "APPROVED",
1713
4447
  Paid: "PAID",
1714
4448
  Rejected: "REJECTED"
1715
4449
  };
4450
+ var CloseoutPackSection = {
4451
+ Summary: "summary",
4452
+ Blockers: "blockers",
4453
+ Handover: "handover",
4454
+ Collections: "collections",
4455
+ Expenses: "expenses",
4456
+ Float: "float",
4457
+ Checklists: "checklists",
4458
+ Forms: "forms",
4459
+ Rooming: "rooming",
4460
+ Seating: "seating",
4461
+ Pickups: "pickups",
4462
+ Vendors: "vendors",
4463
+ Itinerary: "itinerary"
4464
+ };
4465
+ var CollectionMode = {
4466
+ Cash: "CASH",
4467
+ Upi: "UPI",
4468
+ Card: "CARD",
4469
+ Bank: "BANK"
4470
+ };
4471
+ var Currency = {
4472
+ Inr: "INR"
4473
+ };
1716
4474
  var EventType = {
1717
4475
  Trip: "TRIP",
1718
4476
  Trek: "TREK"
1719
4477
  };
4478
+ var ExpenseCategory = {
4479
+ Accom: "ACCOM",
4480
+ Food: "FOOD",
4481
+ Transport: "TRANSPORT",
4482
+ Activity: "ACTIVITY",
4483
+ Misc: "MISC"
4484
+ };
4485
+ var ExpensePaymentMode = {
4486
+ FloatCash: "FLOAT_CASH",
4487
+ Personal: "PERSONAL",
4488
+ Other: "OTHER"
4489
+ };
4490
+ var FileContentType = {
4491
+ ImageJpeg: "image/jpeg",
4492
+ ImagePng: "image/png",
4493
+ ImageWebp: "image/webp",
4494
+ ImageHeic: "image/heic",
4495
+ ApplicationPdf: "application/pdf"
4496
+ };
4497
+ var FilePurpose = {
4498
+ ExpenseReceipt: "expense_receipt",
4499
+ FormAttachment: "form_attachment",
4500
+ BookingVoucher: "booking_voucher"
4501
+ };
4502
+ var FloatDirection = {
4503
+ In: "IN",
4504
+ Out: "OUT"
4505
+ };
1720
4506
  var Gender = {
1721
4507
  Male: "MALE",
1722
4508
  Female: "FEMALE",
1723
4509
  Other: "OTHER",
1724
4510
  Unknown: "UNKNOWN"
1725
4511
  };
4512
+ var ItineraryItemStatusUpdate = {
4513
+ Planned: "PLANNED",
4514
+ Completed: "COMPLETED",
4515
+ Skipped: "SKIPPED"
4516
+ };
4517
+ var ItineraryItemType = {
4518
+ Accommodation: "ACCOMMODATION",
4519
+ Transport: "TRANSPORT",
4520
+ Activity: "ACTIVITY",
4521
+ Meal: "MEAL",
4522
+ Other: "OTHER"
4523
+ };
1726
4524
  var ManagerRole = {
1727
4525
  Manager: "MANAGER",
1728
4526
  Coordinator: "COORDINATOR"
@@ -1738,6 +4536,59 @@ var PartyKind = {
1738
4536
  Corporate: "CORPORATE",
1739
4537
  Other: "OTHER"
1740
4538
  };
4539
+ var PickupKind = {
4540
+ Pickup: "PICKUP",
4541
+ Drop: "DROP"
4542
+ };
4543
+ var RoomingFillOrder = {
4544
+ LargestRoomFirst: "LARGEST_ROOM_FIRST",
4545
+ Sequential: "SEQUENTIAL",
4546
+ Balanced: "BALANCED"
4547
+ };
4548
+ var RoomingGenderPolicy = {
4549
+ StrictSeparate: "STRICT_SEPARATE",
4550
+ GroupMixedOk: "GROUP_MIXED_OK",
4551
+ Off: "OFF"
4552
+ };
4553
+ var RoomingHeuristicKey = {
4554
+ MedicalFirst: "medicalFirst",
4555
+ Couples: "couples",
4556
+ Parties: "parties",
4557
+ Gender: "gender",
4558
+ Diet: "diet",
4559
+ SpreadSolos: "spreadSolos",
4560
+ PartyGenderPolicy: "partyGenderPolicy",
4561
+ SameBus: "sameBus"
4562
+ };
4563
+ var RoomType = {
4564
+ Single: "SINGLE",
4565
+ Twin: "TWIN",
4566
+ Shared: "SHARED",
4567
+ Dorm: "DORM"
4568
+ };
4569
+ var SeatingFillOrder = {
4570
+ Balanced: "BALANCED",
4571
+ FillFirst: "FILL_FIRST",
4572
+ ByStop: "BY_STOP"
4573
+ };
4574
+ var SeatingGenderAdjacency = {
4575
+ Off: "OFF",
4576
+ AvoidUnrelated: "AVOID_UNRELATED",
4577
+ StrictRows: "STRICT_ROWS"
4578
+ };
4579
+ var SeatingHeuristicKey = {
4580
+ MedicalFirst: "medicalFirst",
4581
+ Parties: "parties",
4582
+ SameStop: "sameStop",
4583
+ Gender: "gender",
4584
+ BalanceVehicles: "balanceVehicles"
4585
+ };
4586
+ var SyncOpMethod = {
4587
+ Post: "POST",
4588
+ Patch: "PATCH",
4589
+ Put: "PUT",
4590
+ Delete: "DELETE"
4591
+ };
1741
4592
  var TriggerAnchor = {
1742
4593
  Start: "START",
1743
4594
  End: "END"
@@ -1753,6 +4604,19 @@ var TripStatus = {
1753
4604
  Postponed: "POSTPONED",
1754
4605
  Cancelled: "CANCELLED"
1755
4606
  };
4607
+ var VehicleLayout = {
4608
+ TwoTwo: "TWO_TWO",
4609
+ TwoOne: "TWO_ONE",
4610
+ Flat: "FLAT"
4611
+ };
4612
+ var VehicleType = {
4613
+ Bus: "BUS",
4614
+ TempoTraveller: "TEMPO_TRAVELLER",
4615
+ Car: "CAR",
4616
+ Flight: "FLIGHT",
4617
+ Train: "TRAIN",
4618
+ Other: "OTHER"
4619
+ };
1756
4620
 
1757
4621
  // src/pagination/paginator.ts
1758
4622
  var KaafilPaginationError = class extends Error {
@@ -1776,6 +4640,200 @@ var KaafilPaginationExhaustedError = class _KaafilPaginationExhaustedError exten
1776
4640
  }
1777
4641
  };
1778
4642
 
4643
+ // src/rooming/vocabulary.ts
4644
+ var HEURISTIC_SEVERITY = Object.freeze({
4645
+ medicalFirst: "warn",
4646
+ couples: "warn",
4647
+ parties: "split",
4648
+ gender: "never",
4649
+ diet: "info",
4650
+ spreadSolos: "info",
4651
+ partyGenderPolicy: "info",
4652
+ sameBus: "info"
4653
+ });
4654
+ function isRoomingHeuristicKey(rule) {
4655
+ return Object.hasOwn(HEURISTIC_SEVERITY, rule);
4656
+ }
4657
+ function roomingHeuristicSeverity(rule) {
4658
+ return isRoomingHeuristicKey(rule) ? HEURISTIC_SEVERITY[rule] : void 0;
4659
+ }
4660
+ var TONE_FAMILIES = Object.freeze({
4661
+ [Gender.Male]: "male",
4662
+ [Gender.Female]: "female",
4663
+ [Gender.Other]: "other",
4664
+ [Gender.Unknown]: "unknown"
4665
+ });
4666
+ var UNKNOWN_TONE_FAMILY = TONE_FAMILIES[Gender.Unknown];
4667
+ var SHADES_PER_FAMILY = 8;
4668
+ var FALLBACK_GLYPH = "?";
4669
+ function parseRoomingTone(tone) {
4670
+ const separator = tone.lastIndexOf(".");
4671
+ if (separator <= 0 || separator === tone.length - 1) {
4672
+ return void 0;
4673
+ }
4674
+ const family = tone.slice(0, separator);
4675
+ const rawShade = tone.slice(separator + 1);
4676
+ const shade = Number(rawShade);
4677
+ if (!Number.isInteger(shade) || shade < 0) {
4678
+ return void 0;
4679
+ }
4680
+ return { family, shade };
4681
+ }
4682
+
4683
+ // src/storage/adapter.ts
4684
+ function createInMemoryStorageAdapter() {
4685
+ const store = /* @__PURE__ */ new Map();
4686
+ return {
4687
+ async get(key) {
4688
+ return store.get(key);
4689
+ },
4690
+ async set(key, value) {
4691
+ store.set(key, value);
4692
+ },
4693
+ async remove(key) {
4694
+ store.delete(key);
4695
+ },
4696
+ async clear() {
4697
+ store.clear();
4698
+ }
4699
+ };
4700
+ }
4701
+
4702
+ // src/storage/indexeddb.ts
4703
+ var STORE_NAME = "kv";
4704
+ var DEFAULT_DATABASE_PREFIX = "kaafil-js";
4705
+ var SCHEMA_VERSION = 1;
4706
+ var KaafilIndexedDbUnavailableError = class _KaafilIndexedDbUnavailableError extends Error {
4707
+ reason;
4708
+ constructor(reason, detail) {
4709
+ super(
4710
+ `IndexedDB is not usable in this runtime (${reason})${detail !== void 0 ? `: ${detail}` : ""}. No durable offline store was created. Supply your own KaafilStorageAdapter, or use createInMemoryStorageAdapter() and treat queued writes as process-lifetime only.`
4711
+ );
4712
+ this.name = "KaafilIndexedDbUnavailableError";
4713
+ Object.setPrototypeOf(this, _KaafilIndexedDbUnavailableError.prototype);
4714
+ this.reason = reason;
4715
+ }
4716
+ };
4717
+ function promisifyRequest(request) {
4718
+ return new Promise((resolve, reject) => {
4719
+ request.onsuccess = () => {
4720
+ resolve(request.result);
4721
+ };
4722
+ request.onerror = () => {
4723
+ reject(request.error ?? new Error("IndexedDB request failed with no error attached"));
4724
+ };
4725
+ });
4726
+ }
4727
+ async function openDatabase(factory, databaseName) {
4728
+ return new Promise((resolve, reject) => {
4729
+ let request;
4730
+ try {
4731
+ request = factory.open(databaseName, SCHEMA_VERSION);
4732
+ } catch (error) {
4733
+ reject(
4734
+ new KaafilIndexedDbUnavailableError(
4735
+ "open-failed",
4736
+ error instanceof Error ? error.message : String(error)
4737
+ )
4738
+ );
4739
+ return;
4740
+ }
4741
+ request.onupgradeneeded = () => {
4742
+ const db = request.result;
4743
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
4744
+ db.createObjectStore(STORE_NAME);
4745
+ }
4746
+ };
4747
+ request.onsuccess = () => {
4748
+ const db = request.result;
4749
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
4750
+ db.close();
4751
+ reject(new KaafilIndexedDbUnavailableError("open-failed", "object store missing"));
4752
+ return;
4753
+ }
4754
+ resolve(db);
4755
+ };
4756
+ request.onerror = () => {
4757
+ reject(
4758
+ new KaafilIndexedDbUnavailableError(
4759
+ "open-failed",
4760
+ request.error?.message ?? "open request failed"
4761
+ )
4762
+ );
4763
+ };
4764
+ request.onblocked = () => {
4765
+ reject(new KaafilIndexedDbUnavailableError("blocked"));
4766
+ };
4767
+ });
4768
+ }
4769
+ async function createIndexedDbStorageAdapter(options) {
4770
+ if (typeof options.scope !== "string" || options.scope.length === 0) {
4771
+ throw new TypeError(
4772
+ `"scope" is required and must be a non-empty string \u2014 an unscoped offline store lets one credential's queued writes drain under another's session.`
4773
+ );
4774
+ }
4775
+ const factory = options.indexedDB ?? globalThis.indexedDB;
4776
+ if (factory === void 0 || factory === null) {
4777
+ throw new KaafilIndexedDbUnavailableError("no-indexeddb");
4778
+ }
4779
+ const databaseName = `${options.databasePrefix ?? DEFAULT_DATABASE_PREFIX}:${options.scope}`;
4780
+ const db = await openDatabase(factory, databaseName);
4781
+ const onQuotaExceeded = options.onQuotaExceeded;
4782
+ async function write(run) {
4783
+ return new Promise((resolve, reject) => {
4784
+ let tx;
4785
+ try {
4786
+ tx = db.transaction(STORE_NAME, "readwrite");
4787
+ } catch (error) {
4788
+ reject(error);
4789
+ return;
4790
+ }
4791
+ tx.oncomplete = () => {
4792
+ resolve();
4793
+ };
4794
+ const fail = (error) => {
4795
+ if (error instanceof DOMException && error.name === "QuotaExceededError") {
4796
+ onQuotaExceeded?.(error);
4797
+ }
4798
+ reject(error ?? new Error("IndexedDB transaction failed with no error attached"));
4799
+ };
4800
+ tx.onerror = () => {
4801
+ fail(tx.error);
4802
+ };
4803
+ tx.onabort = () => {
4804
+ fail(tx.error);
4805
+ };
4806
+ try {
4807
+ run(tx.objectStore(STORE_NAME));
4808
+ } catch (error) {
4809
+ fail(error);
4810
+ }
4811
+ });
4812
+ }
4813
+ return {
4814
+ async get(key) {
4815
+ const tx = db.transaction(STORE_NAME, "readonly");
4816
+ const value = await promisifyRequest(tx.objectStore(STORE_NAME).get(key));
4817
+ return typeof value === "string" ? value : void 0;
4818
+ },
4819
+ async set(key, value) {
4820
+ await write((store) => {
4821
+ store.put(value, key);
4822
+ });
4823
+ },
4824
+ async remove(key) {
4825
+ await write((store) => {
4826
+ store.delete(key);
4827
+ });
4828
+ },
4829
+ async clear() {
4830
+ await write((store) => {
4831
+ store.clear();
4832
+ });
4833
+ }
4834
+ };
4835
+ }
4836
+
1779
4837
  // src/client-entry.ts
1780
4838
  function openTokenField(input) {
1781
4839
  switch (input.kind) {
@@ -1902,6 +4960,77 @@ var KaafilClient = class {
1902
4960
  get notifications() {
1903
4961
  return this.#requireState().notifications;
1904
4962
  }
4963
+ get itinerary() {
4964
+ return this.#requireState().itinerary;
4965
+ }
4966
+ get rooming() {
4967
+ return this.#requireState().rooming;
4968
+ }
4969
+ get seating() {
4970
+ return this.#requireState().seating;
4971
+ }
4972
+ get pickups() {
4973
+ return this.#requireState().pickups;
4974
+ }
4975
+ get treks() {
4976
+ return this.#requireState().treks;
4977
+ }
4978
+ get checklists() {
4979
+ return this.#requireState().checklists;
4980
+ }
4981
+ get float() {
4982
+ return this.#requireState().float;
4983
+ }
4984
+ get expenses() {
4985
+ return this.#requireState().expenses;
4986
+ }
4987
+ get collections() {
4988
+ return this.#requireState().collections;
4989
+ }
4990
+ get files() {
4991
+ return this.#requireState().files;
4992
+ }
4993
+ get closeout() {
4994
+ return this.#requireState().closeout;
4995
+ }
4996
+ get sync() {
4997
+ return this.#requireState().sync;
4998
+ }
4999
+ /**
5000
+ * Builds the offline layer on top of THIS open session — the durable
5001
+ * snapshot + outbox, the FIFO drainer, the reconciler, the blob lane and
5002
+ * the batched transport (`06-offline-first.md`).
5003
+ *
5004
+ * The transport is assembled here rather than by the caller, so the
5005
+ * automatic parts stay automatic: the op's fixed idempotency key, the
5006
+ * `If-Match` header, the single-vs-batched wire switch and the consolidated
5007
+ * pull are all wired from the session's own `KaafilHttpClient` and `sync`
5008
+ * resource. What the caller supplies is what only the caller can know — a
5009
+ * durable `storage` adapter for its platform, a `scope` for this
5010
+ * credential, optionally an entity re-reader for conflict reconciliation,
5011
+ * and optionally a conflict resolver (with none, every `409` surfaces,
5012
+ * which is the correct default: `06 §6` forbids auto-merging).
5013
+ *
5014
+ * Throws `KaafilClientNotOpenError` before a session is open — there is no
5015
+ * offline layer without a credential to scope it to.
5016
+ */
5017
+ openOffline(options) {
5018
+ const state = this.#requireState();
5019
+ const transport = createHttpOfflineTransport({
5020
+ http: state.http,
5021
+ sync: state.sync,
5022
+ ...options.readEntity !== void 0 ? { readEntity: options.readEntity } : {},
5023
+ ...options.share !== void 0 ? { credential: "share" } : {}
5024
+ });
5025
+ return createOfflineEngine({
5026
+ storage: options.storage,
5027
+ scope: options.scope,
5028
+ transport,
5029
+ ...options.conflictResolver !== void 0 ? { conflictResolver: options.conflictResolver } : {},
5030
+ ...options.blob !== void 0 ? { blob: options.blob } : {},
5031
+ ...options.share !== void 0 ? { share: options.share } : {}
5032
+ });
5033
+ }
1905
5034
  /**
1906
5035
  * Total teardown. One assignment, no field to forget — see
1907
5036
  * `KaafilClientState` above. Safe to call whether or not a session is
@@ -1970,7 +5099,19 @@ var KaafilClient = class {
1970
5099
  vendors: createVendorsResource(http),
1971
5100
  journey: createJourneyResource(http),
1972
5101
  share: createShareResource(http),
1973
- notifications: createNotificationsResource(http)
5102
+ notifications: createNotificationsResource(http),
5103
+ itinerary: createItineraryResource(http),
5104
+ rooming: createRoomingResource(http),
5105
+ seating: createSeatingResource(http),
5106
+ pickups: createPickupsResource(http),
5107
+ treks: createTreksResource(http),
5108
+ checklists: createChecklistsResource(http),
5109
+ float: createFloatResource(http),
5110
+ expenses: createExpensesResource(http),
5111
+ collections: createCollectionsResource(http),
5112
+ files: createFilesResource(http),
5113
+ closeout: createCloseoutResource(http),
5114
+ sync: createSyncResource(http)
1974
5115
  };
1975
5116
  }
1976
5117
  #requireState() {
@@ -1981,20 +5122,44 @@ var KaafilClient = class {
1981
5122
  }
1982
5123
  };
1983
5124
 
5125
+ exports.ACTIVE_TREK_REF = ACTIVE_TREK_REF;
5126
+ exports.BATCH_THRESHOLD_OPS = BATCH_THRESHOLD_OPS;
5127
+ exports.BlobStatus = BlobStatus;
5128
+ exports.BoardStatus = BoardStatus;
1984
5129
  exports.BookingStatus = BookingStatus;
5130
+ exports.CONSOLIDATED_PULL_THRESHOLD_LISTS = CONSOLIDATED_PULL_THRESHOLD_LISTS;
5131
+ exports.ChecklistAudience = ChecklistAudience;
5132
+ exports.ChecklistGate = ChecklistGate;
5133
+ exports.ChecklistItemStatus = ChecklistItemStatus;
5134
+ exports.ChecklistPhase = ChecklistPhase;
5135
+ exports.ChecklistPullTemplateMode = ChecklistPullTemplateMode;
1985
5136
  exports.ClaimStatusIngest = ClaimStatusIngest;
5137
+ exports.CloseoutPackSection = CloseoutPackSection;
5138
+ exports.CollectionMode = CollectionMode;
5139
+ exports.Currency = Currency;
1986
5140
  exports.ERROR_CODE_TABLE = ERROR_CODE_TABLE;
1987
5141
  exports.EventType = EventType;
5142
+ exports.ExpenseCategory = ExpenseCategory;
5143
+ exports.ExpensePaymentMode = ExpensePaymentMode;
5144
+ exports.FALLBACK_GLYPH = FALLBACK_GLYPH;
5145
+ exports.FileContentType = FileContentType;
5146
+ exports.FilePurpose = FilePurpose;
5147
+ exports.FloatDirection = FloatDirection;
1988
5148
  exports.Gender = Gender;
5149
+ exports.HEURISTIC_SEVERITY = HEURISTIC_SEVERITY;
5150
+ exports.ItineraryItemStatusUpdate = ItineraryItemStatusUpdate;
5151
+ exports.ItineraryItemType = ItineraryItemType;
1989
5152
  exports.KaafilAbortError = KaafilAbortError;
1990
5153
  exports.KaafilApiError = KaafilApiError;
1991
5154
  exports.KaafilCapabilityUnavailableError = KaafilCapabilityUnavailableError;
1992
5155
  exports.KaafilClient = KaafilClient;
1993
5156
  exports.KaafilClientAlreadyOpenError = KaafilClientAlreadyOpenError;
1994
5157
  exports.KaafilClientNotOpenError = KaafilClientNotOpenError;
5158
+ exports.KaafilDeltaCursorInFlightError = KaafilDeltaCursorInFlightError;
1995
5159
  exports.KaafilEntitlementError = KaafilEntitlementError;
1996
5160
  exports.KaafilError = KaafilError;
1997
5161
  exports.KaafilErrorCode = KaafilErrorCode;
5162
+ exports.KaafilIndexedDbUnavailableError = KaafilIndexedDbUnavailableError;
1998
5163
  exports.KaafilInvalidRequestError = KaafilInvalidRequestError;
1999
5164
  exports.KaafilLockedError = KaafilLockedError;
2000
5165
  exports.KaafilNetworkError = KaafilNetworkError;
@@ -2005,6 +5170,8 @@ exports.KaafilPaginationExhaustedError = KaafilPaginationExhaustedError;
2005
5170
  exports.KaafilPaginationInFlightError = KaafilPaginationInFlightError;
2006
5171
  exports.KaafilRateLimitedError = KaafilRateLimitedError;
2007
5172
  exports.KaafilReadOnlyRoleError = KaafilReadOnlyRoleError;
5173
+ exports.KaafilShareBatchUnauthenticatedError = KaafilShareBatchUnauthenticatedError;
5174
+ exports.KaafilShareLinkExpiredError = KaafilShareLinkExpiredError;
2008
5175
  exports.KaafilShareTokenExpiredError = KaafilShareTokenExpiredError;
2009
5176
  exports.KaafilShareTokenRevokedError = KaafilShareTokenRevokedError;
2010
5177
  exports.KaafilTimeoutError = KaafilTimeoutError;
@@ -2012,16 +5179,57 @@ exports.KaafilTransportError = KaafilTransportError;
2012
5179
  exports.KaafilUnauthenticatedError = KaafilUnauthenticatedError;
2013
5180
  exports.KaafilValidationError = KaafilValidationError;
2014
5181
  exports.KaafilVersionConflictError = KaafilVersionConflictError;
5182
+ exports.MAX_BATCH_OPS = MAX_BATCH_OPS;
2015
5183
  exports.ManagerRole = ManagerRole;
2016
5184
  exports.ManifestMode = ManifestMode;
2017
5185
  exports.OutboxClass = OutboxClass;
5186
+ exports.OutboxStatus = OutboxStatus;
2018
5187
  exports.PartyKind = PartyKind;
5188
+ exports.PickupKind = PickupKind;
2019
5189
  exports.Retryability = Retryability;
5190
+ exports.RoomType = RoomType;
5191
+ exports.RoomingFillOrder = RoomingFillOrder;
5192
+ exports.RoomingGenderPolicy = RoomingGenderPolicy;
5193
+ exports.RoomingHeuristicKey = RoomingHeuristicKey;
5194
+ exports.SHADES_PER_FAMILY = SHADES_PER_FAMILY;
5195
+ exports.SHARE_WRITE_GRACE_MS = SHARE_WRITE_GRACE_MS;
5196
+ exports.SYNC_PULL_SECTIONS = SYNC_PULL_SECTIONS;
5197
+ exports.SeatingFillOrder = SeatingFillOrder;
5198
+ exports.SeatingGenderAdjacency = SeatingGenderAdjacency;
5199
+ exports.SeatingHeuristicKey = SeatingHeuristicKey;
5200
+ exports.SyncOpMethod = SyncOpMethod;
5201
+ exports.TONE_FAMILIES = TONE_FAMILIES;
2020
5202
  exports.TriggerAnchor = TriggerAnchor;
2021
5203
  exports.TripMode = TripMode;
2022
5204
  exports.TripStatus = TripStatus;
5205
+ exports.UNKNOWN_TONE_FAMILY = UNKNOWN_TONE_FAMILY;
2023
5206
  exports.UnsatisfiableSchemeError = UnsatisfiableSchemeError;
5207
+ exports.VehicleLayout = VehicleLayout;
5208
+ exports.VehicleType = VehicleType;
5209
+ exports.createBlobLane = createBlobLane;
5210
+ exports.createDeltaCursor = createDeltaCursor;
5211
+ exports.createDrainer = createDrainer;
5212
+ exports.createHttpOfflineTransport = createHttpOfflineTransport;
5213
+ exports.createInMemoryStorageAdapter = createInMemoryStorageAdapter;
5214
+ exports.createIndexedDbStorageAdapter = createIndexedDbStorageAdapter;
5215
+ exports.createOfflineEngine = createOfflineEngine;
5216
+ exports.createOfflineEvents = createOfflineEvents;
5217
+ exports.createOutbox = createOutbox;
5218
+ exports.createPullCoordinator = createPullCoordinator;
5219
+ exports.createShareGuard = createShareGuard;
5220
+ exports.createSnapshotStore = createSnapshotStore;
5221
+ exports.createSyncResource = createSyncResource;
5222
+ exports.extractSectionRows = extractSectionRows;
2024
5223
  exports.isKaafilError = isKaafilError;
2025
5224
  exports.isRetryable = isRetryable;
5225
+ exports.isRoomingHeuristicKey = isRoomingHeuristicKey;
5226
+ exports.isShareBatchPushAvailable = isShareBatchPushAvailable;
5227
+ exports.isTombstone = isTombstone;
5228
+ exports.mergeDeltaRows = mergeDeltaRows;
5229
+ exports.parseRoomingTone = parseRoomingTone;
5230
+ exports.readCurrentVersion = readCurrentVersion;
5231
+ exports.reconcileConflict = reconcileConflict;
5232
+ exports.roomingHeuristicSeverity = roomingHeuristicSeverity;
5233
+ exports.shouldUseBatchTransport = shouldUseBatchTransport;
2026
5234
  //# sourceMappingURL=client-entry.cjs.map
2027
5235
  //# sourceMappingURL=client-entry.cjs.map