kaafil-js 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ interface components {
10
10
  };
11
11
  AddChecklistItemRequest: {
12
12
  /**
13
- * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one.
13
+ * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one. Must match `^[a-z][a-z0-9_]{0,59}$` — snake_case: a leading letter, then lowercase letters, digits and UNDERSCORES only. Hyphens are rejected, which is the usual surprise, since `before-departure` looks lowercase enough.
14
14
  * @example pre_departure_docs
15
15
  */
16
16
  sectionKey: string;
@@ -25,7 +25,7 @@ interface components {
25
25
  */
26
26
  phase: "PRE_DEPARTURE" | "IN_TRIP" | "POST_TRIP";
27
27
  /**
28
- * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one.
28
+ * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one. Must match `^[a-z][a-z0-9_]{0,59}$` — snake_case: a leading letter, then lowercase letters, digits and UNDERSCORES only. Hyphens are rejected, which is the usual surprise, since `before-departure` looks lowercase enough.
29
29
  * @example pre_departure_docs
30
30
  */
31
31
  key?: string;
@@ -324,8 +324,13 @@ interface components {
324
324
  * @example 214
325
325
  */
326
326
  tripsIngested: number;
327
- /** @description ACTIVE_MANAGERS UsageRecord total for the current period. Always 0 today — no writer increments this metric yet (`plan.constants.ts#METERED_USAGE_METRICS`). */
327
+ /** @description ACTIVE_MANAGERS UsageRecord total for the current period — a BILLING METER. Always 0 today: no writer increments this metric yet (`plan.constants.ts#METERED_USAGE_METRICS`). Do NOT render it as a manager count; use `managers`. */
328
328
  activeManagers: number;
329
+ /**
330
+ * @description How many managers this agency has, counted off the Manager table (soft-deleted rows excluded). This is the headcount a 'Managers' column wants — `activeManagers` above is a meter that nothing writes.
331
+ * @example 4
332
+ */
333
+ managers: number;
329
334
  /**
330
335
  * @description When `IngestLog` last recorded a row naming this agency, or `null` if never.
331
336
  * @example 2026-08-14T09:12:00Z
@@ -1585,7 +1590,7 @@ interface components {
1585
1590
  };
1586
1591
  CreateChecklistTemplateRequest: {
1587
1592
  /**
1588
- * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one.
1593
+ * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one. Must match `^[a-z][a-z0-9_]{0,59}$` — snake_case: a leading letter, then lowercase letters, digits and UNDERSCORES only. Hyphens are rejected, which is the usual surprise, since `before-departure` looks lowercase enough.
1589
1594
  * @example pre_departure_docs
1590
1595
  */
1591
1596
  key: string;
@@ -1612,7 +1617,7 @@ interface components {
1612
1617
  /** @description The items this template seeds when pulled. Omit for an empty template. */
1613
1618
  items?: {
1614
1619
  /**
1615
- * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one.
1620
+ * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one. Must match `^[a-z][a-z0-9_]{0,59}$` — snake_case: a leading letter, then lowercase letters, digits and UNDERSCORES only. Hyphens are rejected, which is the usual surprise, since `before-departure` looks lowercase enough.
1616
1621
  * @example pre_departure_docs
1617
1622
  */
1618
1623
  key?: string;
@@ -4847,7 +4852,7 @@ interface components {
4847
4852
  createdAt: string;
4848
4853
  /** @description When this token's row was last changed. */
4849
4854
  updatedAt: string;
4850
- /** @description The plaintext token. Shown exactly once, on this mint response — Kaafil never returns it again and never logs it. Append it to your own link's URL for the traveller to use as their Bearer credential. */
4855
+ /** @description The plaintext token. Never logged. Append it to your own link's URL for the traveller to use as their Bearer credential. You do not have to store it: `GET /share-tokens/{id}/reveal` returns it again, so a desk can re-send a link instead of regenerating one and breaking the copy a family already has. (Tokens minted before Kaafil stored a recoverable copy answer that route with `token: null`.) */
4851
4856
  token: string;
4852
4857
  };
4853
4858
  NotificationListResponse: {
@@ -5213,7 +5218,7 @@ interface components {
5213
5218
  /** @description The FULL replacement item list for this template, in the order they should sort. */
5214
5219
  items?: {
5215
5220
  /**
5216
- * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one.
5221
+ * @description A short, lowercase machine key identifying this section or item within the trip's checklist. Stays stable across pushes so later calls can address the same one. Must match `^[a-z][a-z0-9_]{0,59}$` — snake_case: a leading letter, then lowercase letters, digits and UNDERSCORES only. Hyphens are rejected, which is the usual surprise, since `before-departure` looks lowercase enough.
5217
5222
  * @example pre_departure_docs
5218
5223
  */
5219
5224
  key?: string;
@@ -6068,7 +6073,7 @@ interface components {
6068
6073
  * Format: date-time
6069
6074
  * @description When your system last changed this record. Kaafil uses it to resolve conflicting writes — last-writer-wins by this timestamp, not by arrival order.
6070
6075
  */
6071
- sourceUpdatedAt: string;
6076
+ sourceUpdatedAt?: string;
6072
6077
  /**
6073
6078
  * @description This traveller's booking status on this trip.
6074
6079
  * @enum {string}
@@ -26131,7 +26136,7 @@ interface operations {
26131
26136
  };
26132
26137
  };
26133
26138
  };
26134
- /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `IDEMPOTENCY_KEY_REUSED` — Same Idempotency-Key with a different body (same body replays the stored response); `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule; `OUT_OF_TRIP_WINDOW` — A date/time outside the trip's window */
26139
+ /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `IDEMPOTENCY_KEY_REUSED` — Same Idempotency-Key with a different body (same body replays the stored response); `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule; `OUT_OF_TRIP_WINDOW` — A date/time outside the trip's window; `STAY_WINDOW_OVERLAP` — Two stay windows of one trip claim the same night (half-open intervals); details names the conflicting window */
26135
26140
  422: {
26136
26141
  headers: {
26137
26142
  "X-Request-Id"?: string;
@@ -26141,7 +26146,7 @@ interface operations {
26141
26146
  "application/json": components["schemas"]["ErrorEnvelope"] & {
26142
26147
  error?: {
26143
26148
  /** @enum {string} */
26144
- code?: "VALIDATION_ERROR" | "IDEMPOTENCY_KEY_REUSED" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION" | "OUT_OF_TRIP_WINDOW";
26149
+ code?: "VALIDATION_ERROR" | "IDEMPOTENCY_KEY_REUSED" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION" | "OUT_OF_TRIP_WINDOW" | "STAY_WINDOW_OVERLAP";
26145
26150
  };
26146
26151
  };
26147
26152
  };
@@ -26736,7 +26741,7 @@ interface operations {
26736
26741
  };
26737
26742
  };
26738
26743
  };
26739
- /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule */
26744
+ /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule; `STAY_WINDOW_HAS_ASSIGNMENTS` — Stay-window delete refused: it still holds bed assignments; details carries the occupant and room counts, and ?force=true clears them */
26740
26745
  422: {
26741
26746
  headers: {
26742
26747
  "X-Request-Id"?: string;
@@ -26746,7 +26751,7 @@ interface operations {
26746
26751
  "application/json": components["schemas"]["ErrorEnvelope"] & {
26747
26752
  error?: {
26748
26753
  /** @enum {string} */
26749
- code?: "VALIDATION_ERROR" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION";
26754
+ code?: "VALIDATION_ERROR" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION" | "STAY_WINDOW_HAS_ASSIGNMENTS";
26750
26755
  };
26751
26756
  };
26752
26757
  };
@@ -26896,7 +26901,7 @@ interface operations {
26896
26901
  };
26897
26902
  };
26898
26903
  };
26899
- /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule; `OUT_OF_TRIP_WINDOW` — A date/time outside the trip's window */
26904
+ /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule; `OUT_OF_TRIP_WINDOW` — A date/time outside the trip's window; `STAY_WINDOW_OVERLAP` — Two stay windows of one trip claim the same night (half-open intervals); details names the conflicting window */
26900
26905
  422: {
26901
26906
  headers: {
26902
26907
  "X-Request-Id"?: string;
@@ -26906,7 +26911,7 @@ interface operations {
26906
26911
  "application/json": components["schemas"]["ErrorEnvelope"] & {
26907
26912
  error?: {
26908
26913
  /** @enum {string} */
26909
- code?: "VALIDATION_ERROR" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION" | "OUT_OF_TRIP_WINDOW";
26914
+ code?: "VALIDATION_ERROR" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION" | "OUT_OF_TRIP_WINDOW" | "STAY_WINDOW_OVERLAP";
26910
26915
  };
26911
26916
  };
26912
26917
  };
@@ -34237,6 +34242,148 @@ interface operations {
34237
34242
  };
34238
34243
  };
34239
34244
  };
34245
+ deleteFile: {
34246
+ parameters: {
34247
+ query?: never;
34248
+ header: {
34249
+ "Idempotency-Key"?: string;
34250
+ "If-Match": string;
34251
+ };
34252
+ path: {
34253
+ id: string;
34254
+ };
34255
+ cookie?: never;
34256
+ };
34257
+ requestBody?: never;
34258
+ responses: {
34259
+ /** @description Withdraw a trip document — removes the stored object, then tombstones the row */
34260
+ 204: {
34261
+ headers: {
34262
+ "X-Request-Id"?: string;
34263
+ [name: string]: unknown;
34264
+ };
34265
+ content: {
34266
+ "application/json": components["schemas"]["SuccessEnvelope"] & {
34267
+ /** @enum {boolean} */
34268
+ data: false;
34269
+ };
34270
+ };
34271
+ };
34272
+ /** @description `UNAUTHENTICATED` — Missing/expired credential — the SDK attempts one token refresh first */
34273
+ 401: {
34274
+ headers: {
34275
+ "X-Request-Id"?: string;
34276
+ [name: string]: unknown;
34277
+ };
34278
+ content: {
34279
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34280
+ error?: {
34281
+ /** @enum {string} */
34282
+ code?: "UNAUTHENTICATED";
34283
+ };
34284
+ };
34285
+ };
34286
+ };
34287
+ /** @description `PLAN_FEATURE_DISABLED` — Entitlement flag off for the agency — surface an upgrade prompt */
34288
+ 402: {
34289
+ headers: {
34290
+ "X-Request-Id"?: string;
34291
+ [name: string]: unknown;
34292
+ };
34293
+ content: {
34294
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34295
+ error?: {
34296
+ /** @enum {string} */
34297
+ code?: "PLAN_FEATURE_DISABLED";
34298
+ };
34299
+ };
34300
+ };
34301
+ };
34302
+ /** @description `RESOURCE_NOT_FOUND` — Missing or out-of-scope — the same 404 either way; treat as loss-of-access (purge + surface) */
34303
+ 404: {
34304
+ headers: {
34305
+ "X-Request-Id"?: string;
34306
+ [name: string]: unknown;
34307
+ };
34308
+ content: {
34309
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34310
+ error?: {
34311
+ /** @enum {string} */
34312
+ code?: "RESOURCE_NOT_FOUND";
34313
+ };
34314
+ };
34315
+ };
34316
+ };
34317
+ /** @description `CONFLICT_VERSION` — If-Match/expectedVersion stale; details.currentVersion returned */
34318
+ 409: {
34319
+ headers: {
34320
+ "X-Request-Id"?: string;
34321
+ [name: string]: unknown;
34322
+ };
34323
+ content: {
34324
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34325
+ error?: {
34326
+ /** @enum {string} */
34327
+ code?: "CONFLICT_VERSION";
34328
+ };
34329
+ };
34330
+ };
34331
+ };
34332
+ /** @description `VALIDATION_ERROR` — Body/params fail schema validation; `IDEMPOTENCY_KEY_REUSED` — Same Idempotency-Key with a different body (same body replays the stored response); `CAPABILITY_UNAVAILABLE` — Required ingested data absent or capability mode-inapplicable for the trip — capability dark; `READ_ONLY_ROLE` — Write attempted by a COORDINATOR-role manager token — the role is read-only with no exception; `BUSINESS_RULE_VIOLATION` — A domain guard blocked the write; details names the rule */
34333
+ 422: {
34334
+ headers: {
34335
+ "X-Request-Id"?: string;
34336
+ [name: string]: unknown;
34337
+ };
34338
+ content: {
34339
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34340
+ error?: {
34341
+ /** @enum {string} */
34342
+ code?: "VALIDATION_ERROR" | "IDEMPOTENCY_KEY_REUSED" | "CAPABILITY_UNAVAILABLE" | "READ_ONLY_ROLE" | "BUSINESS_RULE_VIOLATION";
34343
+ };
34344
+ };
34345
+ };
34346
+ };
34347
+ /** @description `RATE_LIMITED` — Per-key/per-token rate limit */
34348
+ 429: {
34349
+ headers: {
34350
+ "X-Request-Id"?: string;
34351
+ /** @description Seconds until the limiter refills enough to accept another request. Integer, never below 1 on a 429 — `decision()` in `rate-limit.ts` floors it at 1 so `Retry-After: 0` ("retry instantly") never ships on an actual refusal. */
34352
+ "Retry-After"?: number;
34353
+ /** @description The ceiling, in requests per window, of the specific limiter tier (IP / API key / share token / bulk-ingest / session-rotation) that refused this request. */
34354
+ "X-RateLimit-Limit"?: number;
34355
+ /** @description Requests remaining in the current window for that tier — always 0 on a 429. */
34356
+ "X-RateLimit-Remaining"?: number;
34357
+ /** @description Seconds until the window resets — relative, not an absolute epoch, so an offline-first client whose clock is wrong cannot misread it. Same value as `Retry-After` on a 429. */
34358
+ "X-RateLimit-Reset"?: number;
34359
+ [name: string]: unknown;
34360
+ };
34361
+ content: {
34362
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34363
+ error?: {
34364
+ /** @enum {string} */
34365
+ code?: "RATE_LIMITED";
34366
+ };
34367
+ };
34368
+ };
34369
+ };
34370
+ /** @description `INTERNAL_ERROR` — Engine fault; safe to retry with backoff (all writes are idempotent); `TENANT_SCOPE_MISSING` — Engine invariant tripped — a query reached the database without tenant scope; always a bug, never client-fixable */
34371
+ 500: {
34372
+ headers: {
34373
+ "X-Request-Id"?: string;
34374
+ [name: string]: unknown;
34375
+ };
34376
+ content: {
34377
+ "application/json": components["schemas"]["ErrorEnvelope"] & {
34378
+ error?: {
34379
+ /** @enum {string} */
34380
+ code?: "INTERNAL_ERROR" | "TENANT_SCOPE_MISSING";
34381
+ };
34382
+ };
34383
+ };
34384
+ };
34385
+ };
34386
+ };
34240
34387
  readFileUrl: {
34241
34388
  parameters: {
34242
34389
  query?: never;
@@ -48343,6 +48490,7 @@ declare const OperationId: {
48343
48490
  readonly DeleteBooking: "deleteBooking";
48344
48491
  readonly DeleteChecklistItem: "deleteChecklistItem";
48345
48492
  readonly DeleteChecklistTemplate: "deleteChecklistTemplate";
48493
+ readonly DeleteFile: "deleteFile";
48346
48494
  readonly DeleteForm: "deleteForm";
48347
48495
  readonly DeleteFormField: "deleteFormField";
48348
48496
  readonly DeleteFormSection: "deleteFormSection";
@@ -51467,6 +51615,18 @@ interface ReadFileUrlOptions {
51467
51615
  interface ListFilesOptions extends ListFilesQuery {
51468
51616
  readonly signal?: AbortSignal;
51469
51617
  }
51618
+ interface DeleteFileOptions {
51619
+ readonly fileId: string;
51620
+ /**
51621
+ * The `version` from the file as last read. Required, not optional: a
51622
+ * missing `If-Match` and a stale one both answer `409 CONFLICT_VERSION`,
51623
+ * identically confusing either way, so this makes forgetting it impossible
51624
+ * rather than merely discouraged. The SDK builds the header itself.
51625
+ */
51626
+ readonly version: number;
51627
+ readonly idempotencyKey?: string;
51628
+ readonly signal?: AbortSignal;
51629
+ }
51470
51630
  interface ReadManagerFileViewOptions {
51471
51631
  readonly fileId: string;
51472
51632
  readonly signal?: AbortSignal;
@@ -51496,6 +51656,29 @@ interface FilesResource {
51496
51656
  * into one manager-doc-viewer-shaped response. See this file's header for
51497
51657
  * why it never refuses on a non-`ready` file the way `url()` does. */
51498
51658
  managerView(options: ReadManagerFileViewOptions): Promise<KaafilResponse<ManagerFileViewResponse>>;
51659
+ /**
51660
+ * `DELETE /api/v1/files/{id}` — withdraw a `trip_document` and DELETE THE
51661
+ * STORED OBJECT. The one call on this resource that destroys bytes.
51662
+ *
51663
+ * `trip_document` ONLY. The other three purposes are evidence owned by a
51664
+ * parent record that decides its own life — a receipt by its expense, an
51665
+ * attachment by its form field, a voucher by its booking (use
51666
+ * `bookings.vouchers.replace`) — so calling this on one is `422
51667
+ * BUSINESS_RULE_VIOLATION`, `details.rule:
51668
+ * "file.deleteRestrictedToTripDocument"`. A `retentionClass` of `financial`
51669
+ * or `consent_evidence` is refused the same way with
51670
+ * `"file.deleteBlockedByRetention"`: those carry an obligation to KEEP.
51671
+ *
51672
+ * Afterwards the id is GONE — `meta()` answers `404`, not the `200`
51673
+ * skeleton a retention-purged file still returns. So unlike a purge, a
51674
+ * withdrawn document cannot be told apart from one that never existed. That
51675
+ * is deliberate; a caller who needs a record of the withdrawal keeps it on
51676
+ * their own side before calling.
51677
+ *
51678
+ * Safe to repeat: a retry after a partial failure finishes the job rather
51679
+ * than erroring.
51680
+ */
51681
+ remove(options: DeleteFileOptions): Promise<KaafilResponse<false>>;
51499
51682
  }
51500
51683
 
51501
51684
  /**
@@ -52108,7 +52291,33 @@ interface ReorderItineraryItemOptions extends ReorderItineraryItemRequest {
52108
52291
  readonly signal?: AbortSignal;
52109
52292
  }
52110
52293
  interface ItineraryItemsResource {
52111
- /** `POST …/itinerary/items` — appends at the tail of its day. */
52294
+ /**
52295
+ * `POST …/itinerary/items` — APPENDS at the tail of its day.
52296
+ *
52297
+ * This is the one write in the ingest path that is not an upsert, and the
52298
+ * asymmetry is worth stating because everything around it is. `trips.upsert`,
52299
+ * `travellers.pushManifest` and `managers.upsert` are all safe to replay —
52300
+ * push the same payload twice and the second is answered `ignored_stale`.
52301
+ * Call this twice with the same title and you get TWO items on that day.
52302
+ *
52303
+ * ── WHY A RETRY DOES NOT SAVE YOU ──────────────────────────────────────────
52304
+ *
52305
+ * `Idempotency-Key` protects the TRANSPORT: the SDK mints one per call
52306
+ * (`../http/client.ts`'s `execute()`), so a socket that dies after the server
52307
+ * committed cannot create the item twice on the automatic retry.
52308
+ *
52309
+ * It does NOT protect an APPLICATION retry. Re-running your seeding script,
52310
+ * or catching an error and calling `add` again, is a NEW call with a NEW
52311
+ * generated key, and the server appends again. The auto-minting is what makes
52312
+ * this easy to miss — the safety is real and it is guarding a different thing.
52313
+ *
52314
+ * ── WHAT TO DO INSTEAD ─────────────────────────────────────────────────────
52315
+ *
52316
+ * Either pass your own stable `idempotencyKey` derived from the content
52317
+ * (`newIdempotencyKey()` in `../idempotency.ts` explains the shape), or read
52318
+ * the day first with `itinerary.read()` and skip titles already on it. A
52319
+ * seeding script that runs more than once wants the second.
52320
+ */
52112
52321
  add(options: AddItineraryItemOptions): Promise<KaafilResponse<ItineraryItemResponse>>;
52113
52322
  patch(options: PatchItineraryItemOptions): Promise<KaafilResponse<ItineraryItemResponse>>;
52114
52323
  /**
@@ -53453,8 +53662,15 @@ type UpsertTripSegmentInput = Omit<UpsertTripSegment, 'startDate' | 'endDate'> &
53453
53662
  readonly endDate: DateTimeInput;
53454
53663
  };
53455
53664
  type PushManifestTraveller = PushManifestRequest['travellers'][number];
53665
+ /**
53666
+ * `sourceUpdatedAt` is OPTIONAL here, unlike every sibling below, because the
53667
+ * wire made it optional for this one entry shape: a desk adding a traveller to
53668
+ * a trip has no "when my system last changed this" instant to send, and the
53669
+ * server stamps the write when it is omitted. A CRM mirroring its own records
53670
+ * still sends its real instant and still wins or loses a race on it.
53671
+ */
53456
53672
  type PushManifestTravellerInput = Omit<PushManifestTraveller, 'sourceUpdatedAt'> & {
53457
- readonly sourceUpdatedAt: DateTimeInput;
53673
+ readonly sourceUpdatedAt?: DateTimeInput;
53458
53674
  };
53459
53675
  type PushBulkTripsTraveller = NonNullable<PushBulkTripsItem['travellers']>[number];
53460
53676
  type PushBulkTripsTravellerInput = Omit<PushBulkTripsTraveller, 'sourceUpdatedAt'> & {