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.
- package/dist/client-entry.cjs +3354 -146
- package/dist/client-entry.cjs.map +1 -1
- package/dist/client-entry.d.cts +1596 -11
- package/dist/client-entry.d.ts +1596 -11
- package/dist/client-entry.js +3288 -147
- package/dist/client-entry.js.map +1 -1
- package/dist/index.cjs +190 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -1899
- package/dist/index.d.ts +63 -1899
- package/dist/index.js +189 -25
- package/dist/index.js.map +1 -1
- package/dist/{paginator-Cs48VeEO.d.cts → vocabulary-BzwP80KV.d.cts} +4891 -1391
- package/dist/{paginator-Cs48VeEO.d.ts → vocabulary-BzwP80KV.d.ts} +4891 -1391
- package/package.json +4 -1
package/dist/client-entry.cjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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/
|
|
1493
|
-
var
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
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: "
|
|
1501
|
-
operationId: OperationId.
|
|
1502
|
-
path: "/api/v1/
|
|
1503
|
-
|
|
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
|
|
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.
|
|
1512
|
-
path: "/api/v1/trips/{ref}/
|
|
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
|
|
1518
|
-
|
|
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.
|
|
1522
|
-
path: "/api/v1/
|
|
1523
|
-
|
|
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
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
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
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
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
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
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/
|
|
1599
|
-
|
|
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
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
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/
|
|
1615
|
-
function
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
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
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
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
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
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
|