@atzentis/booking-sdk 0.1.5 → 0.1.7

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/index.cjs CHANGED
@@ -29,12 +29,16 @@ var index_exports = {};
29
29
  __export(index_exports, {
30
30
  AuthenticationError: () => AuthenticationError,
31
31
  AvailabilityService: () => AvailabilityService,
32
+ BOOKING_STATUSES: () => BOOKING_STATUSES,
33
+ BOOKING_TYPES: () => BOOKING_TYPES,
32
34
  BookingClient: () => BookingClient,
33
35
  BookingError: () => BookingError,
36
+ BookingsService: () => BookingsService,
34
37
  CategoriesService: () => CategoriesService,
35
38
  ConflictError: () => ConflictError,
36
39
  DEFAULT_MODULES: () => DEFAULT_MODULES,
37
40
  ForbiddenError: () => ForbiddenError,
41
+ GuestsService: () => GuestsService,
38
42
  HttpClient: () => HttpClient,
39
43
  NotFoundError: () => NotFoundError,
40
44
  PROPERTY_MODULES: () => PROPERTY_MODULES,
@@ -785,6 +789,244 @@ function minutesToTime(totalMinutes) {
785
789
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
786
790
  }
787
791
 
792
+ // src/services/bookings.ts
793
+ var BookingsService = class extends BaseService {
794
+ constructor() {
795
+ super(...arguments);
796
+ this.basePath = "/booking/v1/bookings";
797
+ }
798
+ // ---------------------------------------------------------------------------
799
+ // CRUD
800
+ // ---------------------------------------------------------------------------
801
+ /**
802
+ * Create a new booking.
803
+ *
804
+ * @example
805
+ * ```typescript
806
+ * const booking = await client.bookings.create({
807
+ * propertyId: "prop_abc123",
808
+ * categoryId: "cat_deluxe",
809
+ * guestId: "guest_42",
810
+ * checkIn: "2025-07-01",
811
+ * checkOut: "2025-07-05",
812
+ * type: "stay",
813
+ * guests: 2,
814
+ * autoConfirm: true,
815
+ * });
816
+ * ```
817
+ */
818
+ create(input) {
819
+ return this._post(this.basePath, input);
820
+ }
821
+ /**
822
+ * Get a single booking by ID.
823
+ *
824
+ * @example
825
+ * ```typescript
826
+ * const booking = await client.bookings.get("bk_abc123");
827
+ * ```
828
+ */
829
+ get(bookingId) {
830
+ return this._get(this._buildPath(bookingId));
831
+ }
832
+ /**
833
+ * List bookings for a property with optional filters and cursor-based pagination.
834
+ *
835
+ * Supports filtering by status, type, guest, date ranges, search term,
836
+ * and custom sort order. Array values for `status` and `type` are serialized
837
+ * as comma-separated strings.
838
+ *
839
+ * @example
840
+ * ```typescript
841
+ * // List all confirmed stay bookings
842
+ * const page = await client.bookings.list({
843
+ * propertyId: "prop_abc123",
844
+ * status: "confirmed",
845
+ * type: "stay",
846
+ * });
847
+ *
848
+ * // Multi-status filter with date range
849
+ * const page2 = await client.bookings.list({
850
+ * propertyId: "prop_abc123",
851
+ * status: ["confirmed", "checked_in"],
852
+ * checkInFrom: "2025-07-01",
853
+ * checkInTo: "2025-07-31",
854
+ * sort: { field: "checkIn", direction: "asc" },
855
+ * limit: 20,
856
+ * });
857
+ * ```
858
+ */
859
+ list(params) {
860
+ const query = {
861
+ propertyId: params.propertyId
862
+ };
863
+ if (params.status !== void 0) {
864
+ query.status = Array.isArray(params.status) ? params.status.join(",") : params.status;
865
+ }
866
+ if (params.type !== void 0) {
867
+ query.type = Array.isArray(params.type) ? params.type.join(",") : params.type;
868
+ }
869
+ if (params.guestId !== void 0) query.guestId = params.guestId;
870
+ if (params.checkInFrom !== void 0) query.checkInFrom = params.checkInFrom;
871
+ if (params.checkInTo !== void 0) query.checkInTo = params.checkInTo;
872
+ if (params.checkOutFrom !== void 0) query.checkOutFrom = params.checkOutFrom;
873
+ if (params.checkOutTo !== void 0) query.checkOutTo = params.checkOutTo;
874
+ if (params.search !== void 0) query.search = params.search;
875
+ if (params.sort !== void 0) {
876
+ query.sort = `${params.sort.field}:${params.sort.direction}`;
877
+ }
878
+ if (params.limit !== void 0) query.limit = params.limit;
879
+ if (params.cursor !== void 0) query.cursor = params.cursor;
880
+ return this._get(this.basePath, query);
881
+ }
882
+ /**
883
+ * Update an existing booking.
884
+ *
885
+ * @example
886
+ * ```typescript
887
+ * const updated = await client.bookings.update("bk_abc123", {
888
+ * guests: 3,
889
+ * notes: "Extra bed requested",
890
+ * });
891
+ * ```
892
+ */
893
+ update(bookingId, input) {
894
+ return this._patch(this._buildPath(bookingId), input);
895
+ }
896
+ /**
897
+ * Delete a booking.
898
+ *
899
+ * @example
900
+ * ```typescript
901
+ * await client.bookings.delete("bk_abc123");
902
+ * ```
903
+ */
904
+ delete(bookingId) {
905
+ return this._delete(this._buildPath(bookingId));
906
+ }
907
+ // ---------------------------------------------------------------------------
908
+ // Lifecycle — happy path
909
+ // ---------------------------------------------------------------------------
910
+ /**
911
+ * Confirm a pending booking.
912
+ *
913
+ * Transitions: `pending` → `confirmed`
914
+ *
915
+ * @throws {ConflictError} 409 if the booking is not in `pending` status
916
+ *
917
+ * @example
918
+ * ```typescript
919
+ * const confirmed = await client.bookings.confirm("bk_abc123");
920
+ * // confirmed.status === "confirmed"
921
+ * // confirmed.confirmedAt is populated
922
+ * ```
923
+ */
924
+ confirm(bookingId) {
925
+ return this._post(this._buildPath(bookingId, "confirm"), {});
926
+ }
927
+ /**
928
+ * Check in a guest.
929
+ *
930
+ * Transitions: `confirmed` → `checked_in`
931
+ *
932
+ * @throws {ConflictError} 409 if the booking is not in `confirmed` status
933
+ *
934
+ * @example
935
+ * ```typescript
936
+ * const checkedIn = await client.bookings.checkIn("bk_abc123", {
937
+ * actualArrival: "2025-07-01T14:30:00Z",
938
+ * });
939
+ * // checkedIn.status === "checked_in"
940
+ * // checkedIn.checkedInAt is populated
941
+ * ```
942
+ */
943
+ checkIn(bookingId, input) {
944
+ return this._post(this._buildPath(bookingId, "check-in"), input ?? {});
945
+ }
946
+ /**
947
+ * Check out a guest.
948
+ *
949
+ * Transitions: `checked_in` → `checked_out`
950
+ *
951
+ * @throws {ConflictError} 409 if the booking is not in `checked_in` status
952
+ *
953
+ * @example
954
+ * ```typescript
955
+ * const checkedOut = await client.bookings.checkOut("bk_abc123", {
956
+ * actualDeparture: "2025-07-05T11:00:00Z",
957
+ * });
958
+ * // checkedOut.status === "checked_out"
959
+ * // checkedOut.checkedOutAt is populated
960
+ * ```
961
+ */
962
+ checkOut(bookingId, input) {
963
+ return this._post(this._buildPath(bookingId, "check-out"), input ?? {});
964
+ }
965
+ // ---------------------------------------------------------------------------
966
+ // Lifecycle — alternate endings
967
+ // ---------------------------------------------------------------------------
968
+ /**
969
+ * Cancel a booking.
970
+ *
971
+ * Transitions: `pending` | `confirmed` | `checked_in` → `cancelled`
972
+ *
973
+ * @throws {ConflictError} 409 if the booking is already cancelled, checked out, or no-show
974
+ *
975
+ * @example
976
+ * ```typescript
977
+ * const cancelled = await client.bookings.cancel("bk_abc123", {
978
+ * reason: "Guest requested cancellation",
979
+ * refundRequested: true,
980
+ * });
981
+ * // cancelled.status === "cancelled"
982
+ * // cancelled.cancelledAt is populated
983
+ * // cancelled.cancellationReason === "Guest requested cancellation"
984
+ * ```
985
+ */
986
+ cancel(bookingId, input) {
987
+ return this._post(this._buildPath(bookingId, "cancel"), input);
988
+ }
989
+ /**
990
+ * Mark a booking as no-show.
991
+ *
992
+ * Transitions: `pending` | `confirmed` | `checked_in` → `no_show`
993
+ *
994
+ * @throws {ConflictError} 409 if the booking is already checked out, cancelled, or no-show
995
+ *
996
+ * @example
997
+ * ```typescript
998
+ * const noShow = await client.bookings.noShow("bk_abc123", {
999
+ * chargeNoShowFee: true,
1000
+ * });
1001
+ * // noShow.status === "no_show"
1002
+ * // noShow.noShowAt is populated
1003
+ * ```
1004
+ */
1005
+ noShow(bookingId, input) {
1006
+ return this._post(this._buildPath(bookingId, "no-show"), input ?? {});
1007
+ }
1008
+ /**
1009
+ * Assign or reassign a space to a booking.
1010
+ *
1011
+ * Can be called on any active booking (pending, confirmed, checked_in).
1012
+ *
1013
+ * @throws {ConflictError} 409 if the booking is in a terminal status
1014
+ *
1015
+ * @example
1016
+ * ```typescript
1017
+ * const assigned = await client.bookings.assignSpace("bk_abc123", {
1018
+ * spaceId: "spc_room101",
1019
+ * notes: "Upgraded to deluxe",
1020
+ * });
1021
+ * // assigned.spaceId === "spc_room101"
1022
+ * // assigned.space is populated
1023
+ * ```
1024
+ */
1025
+ assignSpace(bookingId, input) {
1026
+ return this._post(this._buildPath(bookingId, "assign-space"), input);
1027
+ }
1028
+ };
1029
+
788
1030
  // src/services/categories.ts
789
1031
  var CategoriesService = class extends BaseService {
790
1032
  constructor() {
@@ -850,6 +1092,285 @@ var CategoriesService = class extends BaseService {
850
1092
  }
851
1093
  };
852
1094
 
1095
+ // src/services/guests.ts
1096
+ var GuestsService = class extends BaseService {
1097
+ constructor() {
1098
+ super(...arguments);
1099
+ this.basePath = "/guest/v1/profiles";
1100
+ }
1101
+ // ---------------------------------------------------------------------------
1102
+ // CRUD
1103
+ // ---------------------------------------------------------------------------
1104
+ /**
1105
+ * Create a new guest profile.
1106
+ *
1107
+ * @example
1108
+ * ```typescript
1109
+ * const guest = await client.guests.create({
1110
+ * firstName: "Maria",
1111
+ * lastName: "Papadopoulou",
1112
+ * email: "maria@example.com",
1113
+ * phone: "+30 210 1234567",
1114
+ * nationality: "GR",
1115
+ * });
1116
+ * ```
1117
+ */
1118
+ create(input) {
1119
+ return this._post(this.basePath, input);
1120
+ }
1121
+ /**
1122
+ * Get a single guest by ID.
1123
+ *
1124
+ * @example
1125
+ * ```typescript
1126
+ * const guest = await client.guests.get("guest_42");
1127
+ * ```
1128
+ */
1129
+ get(guestId) {
1130
+ return this._get(this._buildPath(guestId));
1131
+ }
1132
+ /**
1133
+ * List guests with optional filters and cursor-based pagination.
1134
+ *
1135
+ * @example
1136
+ * ```typescript
1137
+ * const page = await client.guests.list({
1138
+ * tags: ["vip", "returning"],
1139
+ * sort: { field: "lastName", direction: "asc" },
1140
+ * limit: 20,
1141
+ * });
1142
+ * ```
1143
+ */
1144
+ list(params) {
1145
+ if (!params) {
1146
+ return this._get(this.basePath);
1147
+ }
1148
+ const query = {};
1149
+ if (params.tags !== void 0 && params.tags.length > 0) {
1150
+ query.tags = params.tags.join(",");
1151
+ }
1152
+ if (params.source !== void 0) query.source = params.source;
1153
+ if (params.createdFrom !== void 0) query.createdFrom = params.createdFrom;
1154
+ if (params.createdTo !== void 0) query.createdTo = params.createdTo;
1155
+ if (params.sort !== void 0) {
1156
+ query.sort = `${params.sort.field}:${params.sort.direction}`;
1157
+ }
1158
+ if (params.limit !== void 0) query.limit = params.limit;
1159
+ if (params.cursor !== void 0) query.cursor = params.cursor;
1160
+ return this._get(this.basePath, query);
1161
+ }
1162
+ /**
1163
+ * Update an existing guest profile.
1164
+ *
1165
+ * @example
1166
+ * ```typescript
1167
+ * const updated = await client.guests.update("guest_42", {
1168
+ * email: "maria.new@example.com",
1169
+ * tags: ["vip"],
1170
+ * });
1171
+ * ```
1172
+ */
1173
+ update(guestId, input) {
1174
+ return this._patch(this._buildPath(guestId), input);
1175
+ }
1176
+ /**
1177
+ * Delete a guest profile (soft-delete).
1178
+ *
1179
+ * @example
1180
+ * ```typescript
1181
+ * await client.guests.delete("guest_42");
1182
+ * ```
1183
+ */
1184
+ delete(guestId) {
1185
+ return this._delete(this._buildPath(guestId));
1186
+ }
1187
+ // ---------------------------------------------------------------------------
1188
+ // Search and Duplicate Detection
1189
+ // ---------------------------------------------------------------------------
1190
+ /**
1191
+ * Search guests by name, email, phone, or passport number.
1192
+ *
1193
+ * Returns results sorted by relevance score (highest first).
1194
+ *
1195
+ * @param query - Search query string
1196
+ * @param params - Optional search parameters (limit, fields)
1197
+ *
1198
+ * @example
1199
+ * ```typescript
1200
+ * // Search by name
1201
+ * const results = await client.guests.search("Papadopoulos");
1202
+ *
1203
+ * // Search by email with field filter
1204
+ * const results2 = await client.guests.search("maria@", {
1205
+ * fields: ["email"],
1206
+ * limit: 5,
1207
+ * });
1208
+ * ```
1209
+ */
1210
+ search(query, params) {
1211
+ const searchQuery = {
1212
+ q: query
1213
+ };
1214
+ if (params?.limit !== void 0) searchQuery.limit = params.limit;
1215
+ if (params?.fields !== void 0 && params.fields.length > 0) {
1216
+ searchQuery.fields = params.fields.join(",");
1217
+ }
1218
+ return this._get(this._buildPath("search"), searchQuery);
1219
+ }
1220
+ /**
1221
+ * Find potential duplicate profiles for a guest.
1222
+ *
1223
+ * Returns candidates sorted by confidence score (highest first).
1224
+ *
1225
+ * @throws {NotFoundError} 404 if the guest is not found
1226
+ *
1227
+ * @example
1228
+ * ```typescript
1229
+ * const duplicates = await client.guests.findDuplicates("guest_42");
1230
+ * for (const dup of duplicates.data) {
1231
+ * console.log(`${dup.guest.firstName} — ${dup.confidence} (${dup.matchedFields})`);
1232
+ * }
1233
+ * ```
1234
+ */
1235
+ findDuplicates(guestId) {
1236
+ return this._get(this._buildPath(guestId, "duplicates"));
1237
+ }
1238
+ // ---------------------------------------------------------------------------
1239
+ // Merge
1240
+ // ---------------------------------------------------------------------------
1241
+ /**
1242
+ * Merge duplicate guest profiles into a primary profile.
1243
+ *
1244
+ * **Warning: This operation is irreversible.** All history from duplicate
1245
+ * profiles is transferred to the primary. Duplicate profiles are soft-deleted.
1246
+ *
1247
+ * @throws {NotFoundError} 404 if primary or any duplicate is not found
1248
+ * @throws {ConflictError} 409 if attempting to merge a guest into itself
1249
+ * @throws {ValidationError} 400 if duplicateIds is empty
1250
+ *
1251
+ * @example
1252
+ * ```typescript
1253
+ * const merged = await client.guests.merge("guest_primary", {
1254
+ * duplicateIds: ["guest_dup1", "guest_dup2"],
1255
+ * });
1256
+ * ```
1257
+ */
1258
+ merge(primaryId, input) {
1259
+ return this._post(this._buildPath(primaryId, "merge"), input);
1260
+ }
1261
+ // ---------------------------------------------------------------------------
1262
+ // Preferences
1263
+ // ---------------------------------------------------------------------------
1264
+ /**
1265
+ * Get guest preferences.
1266
+ *
1267
+ * Returns default/empty preferences if none have been set (does not throw 404).
1268
+ *
1269
+ * @throws {NotFoundError} 404 if the guest is not found
1270
+ *
1271
+ * @example
1272
+ * ```typescript
1273
+ * const prefs = await client.guests.getPreferences("guest_42");
1274
+ * console.log(prefs.dietary, prefs.roomType);
1275
+ * ```
1276
+ */
1277
+ getPreferences(guestId) {
1278
+ return this._get(this._buildPath(guestId, "preferences"));
1279
+ }
1280
+ /**
1281
+ * Update guest preferences (partial merge).
1282
+ *
1283
+ * Only provided fields are updated; unspecified fields retain their values.
1284
+ *
1285
+ * @throws {NotFoundError} 404 if the guest is not found
1286
+ *
1287
+ * @example
1288
+ * ```typescript
1289
+ * const updated = await client.guests.updatePreferences("guest_42", {
1290
+ * dietary: ["vegetarian"],
1291
+ * roomType: "suite",
1292
+ * custom: { pillow: "firm" },
1293
+ * });
1294
+ * ```
1295
+ */
1296
+ updatePreferences(guestId, input) {
1297
+ return this._patch(this._buildPath(guestId, "preferences"), input);
1298
+ }
1299
+ // ---------------------------------------------------------------------------
1300
+ // Cross-Domain History
1301
+ // ---------------------------------------------------------------------------
1302
+ /**
1303
+ * Get a guest's booking history.
1304
+ *
1305
+ * Returns lightweight booking summaries with pagination support.
1306
+ *
1307
+ * @throws {NotFoundError} 404 if the guest is not found
1308
+ *
1309
+ * @example
1310
+ * ```typescript
1311
+ * const bookings = await client.guests.getBookings("guest_42", {
1312
+ * from: "2025-01-01",
1313
+ * to: "2025-12-31",
1314
+ * limit: 10,
1315
+ * });
1316
+ * ```
1317
+ */
1318
+ getBookings(guestId, params) {
1319
+ return this._get(
1320
+ this._buildPath(guestId, "bookings"),
1321
+ params ? this._buildHistoryQuery(params) : void 0
1322
+ );
1323
+ }
1324
+ /**
1325
+ * Get a guest's folio history.
1326
+ *
1327
+ * Returns lightweight folio summaries with pagination support.
1328
+ *
1329
+ * @throws {NotFoundError} 404 if the guest is not found
1330
+ *
1331
+ * @example
1332
+ * ```typescript
1333
+ * const folios = await client.guests.getFolios("guest_42");
1334
+ * ```
1335
+ */
1336
+ getFolios(guestId, params) {
1337
+ return this._get(
1338
+ this._buildPath(guestId, "folios"),
1339
+ params ? this._buildHistoryQuery(params) : void 0
1340
+ );
1341
+ }
1342
+ /**
1343
+ * Get a guest's order history.
1344
+ *
1345
+ * Returns lightweight order summaries with pagination support.
1346
+ *
1347
+ * @throws {NotFoundError} 404 if the guest is not found
1348
+ *
1349
+ * @example
1350
+ * ```typescript
1351
+ * const orders = await client.guests.getOrders("guest_42", {
1352
+ * limit: 5,
1353
+ * cursor: "next_page",
1354
+ * });
1355
+ * ```
1356
+ */
1357
+ getOrders(guestId, params) {
1358
+ return this._get(
1359
+ this._buildPath(guestId, "orders"),
1360
+ params ? this._buildHistoryQuery(params) : void 0
1361
+ );
1362
+ }
1363
+ /** Build query params from GuestHistoryParams, omitting undefined values */
1364
+ _buildHistoryQuery(params) {
1365
+ const query = {};
1366
+ if (params.limit !== void 0) query.limit = params.limit;
1367
+ if (params.cursor !== void 0) query.cursor = params.cursor;
1368
+ if (params.from !== void 0) query.from = params.from;
1369
+ if (params.to !== void 0) query.to = params.to;
1370
+ return query;
1371
+ }
1372
+ };
1373
+
853
1374
  // src/services/properties.ts
854
1375
  var PropertiesService = class extends BaseService {
855
1376
  constructor() {
@@ -1074,6 +1595,16 @@ var BookingClient = class {
1074
1595
  this._availability ?? (this._availability = new AvailabilityService(this.httpClient));
1075
1596
  return this._availability;
1076
1597
  }
1598
+ /** Bookings service — lazy-initialized on first access */
1599
+ get bookings() {
1600
+ this._bookings ?? (this._bookings = new BookingsService(this.httpClient));
1601
+ return this._bookings;
1602
+ }
1603
+ /** Guests service — lazy-initialized on first access */
1604
+ get guests() {
1605
+ this._guests ?? (this._guests = new GuestsService(this.httpClient));
1606
+ return this._guests;
1607
+ }
1077
1608
  /** Properties service — lazy-initialized on first access */
1078
1609
  get properties() {
1079
1610
  this._properties ?? (this._properties = new PropertiesService(this.httpClient));
@@ -1128,6 +1659,27 @@ async function firstPage(fetcher, options) {
1128
1659
  return fetcher({ ...options ?? {} });
1129
1660
  }
1130
1661
 
1662
+ // src/types/bookings.ts
1663
+ var BOOKING_TYPES = [
1664
+ "stay",
1665
+ "table",
1666
+ "service",
1667
+ "parking",
1668
+ "desk",
1669
+ "meeting",
1670
+ "dayuse",
1671
+ "custom"
1672
+ ];
1673
+ var BOOKING_STATUSES = [
1674
+ "pending",
1675
+ "confirmed",
1676
+ "checked_in",
1677
+ "checked_out",
1678
+ "cancelled",
1679
+ "no_show",
1680
+ "waitlist"
1681
+ ];
1682
+
1131
1683
  // src/types/properties.ts
1132
1684
  var PROPERTY_MODULES = [
1133
1685
  "booking",
@@ -1178,12 +1730,16 @@ var VERSION = "0.1.0";
1178
1730
  0 && (module.exports = {
1179
1731
  AuthenticationError,
1180
1732
  AvailabilityService,
1733
+ BOOKING_STATUSES,
1734
+ BOOKING_TYPES,
1181
1735
  BookingClient,
1182
1736
  BookingError,
1737
+ BookingsService,
1183
1738
  CategoriesService,
1184
1739
  ConflictError,
1185
1740
  DEFAULT_MODULES,
1186
1741
  ForbiddenError,
1742
+ GuestsService,
1187
1743
  HttpClient,
1188
1744
  NotFoundError,
1189
1745
  PROPERTY_MODULES,