@atzentis/booking-sdk 0.1.3 → 0.1.5
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 +428 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +561 -24
- package/dist/index.d.ts +561 -24
- package/dist/index.js +424 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -475,6 +475,267 @@ var BaseService = class {
|
|
|
475
475
|
}
|
|
476
476
|
};
|
|
477
477
|
|
|
478
|
+
// src/services/availability.ts
|
|
479
|
+
var AvailabilityService = class extends BaseService {
|
|
480
|
+
constructor() {
|
|
481
|
+
super(...arguments);
|
|
482
|
+
this.basePath = "/booking/v1/availability";
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Check availability for a property and date range.
|
|
486
|
+
*
|
|
487
|
+
* @param params - Must include `propertyId`, `checkIn`, `checkOut`; supports optional filters
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* const result = await booking.availability.check({
|
|
492
|
+
* propertyId: "prop_abc123",
|
|
493
|
+
* checkIn: "2025-06-01",
|
|
494
|
+
* checkOut: "2025-06-05",
|
|
495
|
+
* type: "room",
|
|
496
|
+
* guests: 2,
|
|
497
|
+
* });
|
|
498
|
+
* ```
|
|
499
|
+
*/
|
|
500
|
+
check(params) {
|
|
501
|
+
const { propertyId, checkIn, checkOut, categoryId, spaceId, guests, type } = params;
|
|
502
|
+
return this._get(this.basePath, {
|
|
503
|
+
propertyId,
|
|
504
|
+
checkIn,
|
|
505
|
+
checkOut,
|
|
506
|
+
categoryId,
|
|
507
|
+
spaceId,
|
|
508
|
+
guests,
|
|
509
|
+
type
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Search availability across multiple properties.
|
|
514
|
+
*
|
|
515
|
+
* @param params - Must include `propertyIds`, `checkIn`, `checkOut`; supports filtering and pagination
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```typescript
|
|
519
|
+
* const results = await booking.availability.search({
|
|
520
|
+
* propertyIds: ["prop_abc", "prop_def"],
|
|
521
|
+
* checkIn: "2025-06-01",
|
|
522
|
+
* checkOut: "2025-06-05",
|
|
523
|
+
* guests: 2,
|
|
524
|
+
* priceRange: { min: 5000, max: 20000 },
|
|
525
|
+
* });
|
|
526
|
+
* ```
|
|
527
|
+
*/
|
|
528
|
+
search(params) {
|
|
529
|
+
return this._post(this.basePath, params);
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Generate a calendar view of daily availability for a property.
|
|
533
|
+
*
|
|
534
|
+
* Client-side helper that calls `check()` internally and transforms the result
|
|
535
|
+
* into a `CalendarDay[]` suitable for calendar UI rendering.
|
|
536
|
+
*
|
|
537
|
+
* @param params - Extends `AvailabilityCheckParams` with optional `months` (default: 1)
|
|
538
|
+
*
|
|
539
|
+
* @example
|
|
540
|
+
* ```typescript
|
|
541
|
+
* const calendar = await booking.availability.getCalendar({
|
|
542
|
+
* propertyId: "prop_abc123",
|
|
543
|
+
* checkIn: "2025-06-01",
|
|
544
|
+
* checkOut: "2025-06-30",
|
|
545
|
+
* });
|
|
546
|
+
* ```
|
|
547
|
+
*/
|
|
548
|
+
async getCalendar(params) {
|
|
549
|
+
const { months, ...checkParams } = params;
|
|
550
|
+
let endDate;
|
|
551
|
+
if (checkParams.checkOut !== checkParams.checkIn) {
|
|
552
|
+
endDate = checkParams.checkOut;
|
|
553
|
+
} else if (months != null) {
|
|
554
|
+
endDate = addDays(checkParams.checkIn, months * 30);
|
|
555
|
+
} else {
|
|
556
|
+
return [];
|
|
557
|
+
}
|
|
558
|
+
const dates = generateDateRange(checkParams.checkIn, endDate, 365);
|
|
559
|
+
if (dates.length === 0) return [];
|
|
560
|
+
const result = await this.check({ ...checkParams, checkOut: endDate });
|
|
561
|
+
const spacesAvailable = result.spaces.filter((s) => s.available).length;
|
|
562
|
+
return dates.map((date) => ({
|
|
563
|
+
date,
|
|
564
|
+
available: result.available,
|
|
565
|
+
price: result.available && result.pricing ? result.pricing.total : null,
|
|
566
|
+
minStay: result.restrictions?.minStay ?? null,
|
|
567
|
+
closedToArrival: result.restrictions?.closedToArrival ?? false,
|
|
568
|
+
closedToDeparture: result.restrictions?.closedToDeparture ?? false,
|
|
569
|
+
spacesAvailable: result.available ? spacesAvailable : 0
|
|
570
|
+
}));
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get available table reservation time slots for a specific date.
|
|
574
|
+
*
|
|
575
|
+
* Client-side helper for the Tables vertical. Calls `check()` internally
|
|
576
|
+
* with `type: "table"` and reshapes the response into `TimeSlot[]`.
|
|
577
|
+
*
|
|
578
|
+
* @param params - Must include `propertyId` and `date`
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* ```typescript
|
|
582
|
+
* const slots = await booking.availability.getTableSlots({
|
|
583
|
+
* propertyId: "prop_abc123",
|
|
584
|
+
* date: "2025-06-15",
|
|
585
|
+
* guests: 4,
|
|
586
|
+
* });
|
|
587
|
+
* ```
|
|
588
|
+
*/
|
|
589
|
+
async getTableSlots(params) {
|
|
590
|
+
const { date, guests, categoryId, duration, ...rest } = params;
|
|
591
|
+
const result = await this.check({
|
|
592
|
+
...rest,
|
|
593
|
+
checkIn: date,
|
|
594
|
+
checkOut: date,
|
|
595
|
+
type: "table",
|
|
596
|
+
guests,
|
|
597
|
+
categoryId
|
|
598
|
+
});
|
|
599
|
+
if (!result.available || result.spaces.length === 0) {
|
|
600
|
+
return [];
|
|
601
|
+
}
|
|
602
|
+
const slotDuration = duration ?? 90;
|
|
603
|
+
const availableSpaces = result.spaces.filter((s) => s.available);
|
|
604
|
+
return availableSpaces.map((space, index) => ({
|
|
605
|
+
startTime: minutesToTime(11 * 60 + index * slotDuration),
|
|
606
|
+
endTime: minutesToTime(11 * 60 + index * slotDuration + slotDuration),
|
|
607
|
+
available: true,
|
|
608
|
+
tablesAvailable: availableSpaces.length,
|
|
609
|
+
price: space.price
|
|
610
|
+
}));
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Get available service appointment slots for a specific date.
|
|
614
|
+
*
|
|
615
|
+
* Client-side helper for the Services vertical. Calls `check()` internally
|
|
616
|
+
* with `type: "service"` and reshapes the response into `ServiceTimeSlot[]`.
|
|
617
|
+
*
|
|
618
|
+
* @param params - Must include `propertyId` and `date`
|
|
619
|
+
*
|
|
620
|
+
* @example
|
|
621
|
+
* ```typescript
|
|
622
|
+
* const slots = await booking.availability.getServiceSlots({
|
|
623
|
+
* propertyId: "prop_abc123",
|
|
624
|
+
* date: "2025-06-15",
|
|
625
|
+
* providerId: "staff_001",
|
|
626
|
+
* duration: 60,
|
|
627
|
+
* });
|
|
628
|
+
* ```
|
|
629
|
+
*/
|
|
630
|
+
async getServiceSlots(params) {
|
|
631
|
+
const { date, providerId, categoryId, duration, ...rest } = params;
|
|
632
|
+
const result = await this.check({
|
|
633
|
+
...rest,
|
|
634
|
+
checkIn: date,
|
|
635
|
+
checkOut: date,
|
|
636
|
+
type: "service",
|
|
637
|
+
categoryId
|
|
638
|
+
});
|
|
639
|
+
if (!result.available || result.spaces.length === 0) {
|
|
640
|
+
return [];
|
|
641
|
+
}
|
|
642
|
+
const slotDuration = duration ?? 60;
|
|
643
|
+
const availableSpaces = result.spaces.filter((s) => s.available);
|
|
644
|
+
return availableSpaces.map((space, index) => ({
|
|
645
|
+
startTime: minutesToTime(9 * 60 + index * slotDuration),
|
|
646
|
+
endTime: minutesToTime(9 * 60 + index * slotDuration + slotDuration),
|
|
647
|
+
available: true,
|
|
648
|
+
tablesAvailable: availableSpaces.length,
|
|
649
|
+
price: space.price,
|
|
650
|
+
providerId: providerId ?? space.spaceId,
|
|
651
|
+
providerName: space.name
|
|
652
|
+
}));
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Get aggregated pricing statistics for a property and date range.
|
|
656
|
+
*
|
|
657
|
+
* Client-side helper that calls `check()` internally and computes
|
|
658
|
+
* min/max/average/total pricing from available spaces.
|
|
659
|
+
*
|
|
660
|
+
* @param params - Extends `AvailabilityCheckParams` with optional `currency`
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```typescript
|
|
664
|
+
* const pricing = await booking.availability.getPricing({
|
|
665
|
+
* propertyId: "prop_abc123",
|
|
666
|
+
* checkIn: "2025-06-01",
|
|
667
|
+
* checkOut: "2025-06-05",
|
|
668
|
+
* });
|
|
669
|
+
* console.log(`From €${pricing.minPrice / 100} to €${pricing.maxPrice / 100}`);
|
|
670
|
+
* ```
|
|
671
|
+
*/
|
|
672
|
+
async getPricing(params) {
|
|
673
|
+
const { currency: requestedCurrency, ...checkParams } = params;
|
|
674
|
+
const result = await this.check(checkParams);
|
|
675
|
+
const availableSpaces = result.spaces.filter((s) => s.available);
|
|
676
|
+
const nights = dateDiffDays(params.checkIn, params.checkOut);
|
|
677
|
+
const currency = requestedCurrency ?? result.pricing?.currency ?? "EUR";
|
|
678
|
+
if (availableSpaces.length === 0) {
|
|
679
|
+
return {
|
|
680
|
+
minPrice: 0,
|
|
681
|
+
maxPrice: 0,
|
|
682
|
+
averagePrice: 0,
|
|
683
|
+
totalPrice: 0,
|
|
684
|
+
perNight: null,
|
|
685
|
+
nights,
|
|
686
|
+
currency
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
const prices = availableSpaces.map((s) => s.price);
|
|
690
|
+
const minPrice = Math.min(...prices);
|
|
691
|
+
const maxPrice = Math.max(...prices);
|
|
692
|
+
const averagePrice = Math.round(prices.reduce((sum, p) => sum + p, 0) / prices.length);
|
|
693
|
+
const totalPrice = result.pricing?.total ?? averagePrice * Math.max(nights, 1);
|
|
694
|
+
const perNight = nights > 0 ? Math.round(totalPrice / nights) : null;
|
|
695
|
+
return { minPrice, maxPrice, averagePrice, totalPrice, perNight, nights, currency };
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
function parseDateStr(dateStr) {
|
|
699
|
+
const parts = dateStr.split("-");
|
|
700
|
+
return [Number(parts[0]), Number(parts[1]), Number(parts[2])];
|
|
701
|
+
}
|
|
702
|
+
function addDays(dateStr, days) {
|
|
703
|
+
const [year, month, day] = parseDateStr(dateStr);
|
|
704
|
+
return formatDate(new Date(Date.UTC(year, month - 1, day + days)));
|
|
705
|
+
}
|
|
706
|
+
function generateDateRange(start, end, maxDays) {
|
|
707
|
+
const [sy, sm, sd] = parseDateStr(start);
|
|
708
|
+
const [ey, em, ed] = parseDateStr(end);
|
|
709
|
+
const startMs = Date.UTC(sy, sm - 1, sd);
|
|
710
|
+
const endMs = Date.UTC(ey, em - 1, ed);
|
|
711
|
+
if (endMs <= startMs) return [];
|
|
712
|
+
const msPerDay = 864e5;
|
|
713
|
+
const totalDays = Math.min(Math.floor((endMs - startMs) / msPerDay), maxDays);
|
|
714
|
+
const dates = [];
|
|
715
|
+
for (let i = 0; i < totalDays; i++) {
|
|
716
|
+
dates.push(formatDate(new Date(startMs + i * msPerDay)));
|
|
717
|
+
}
|
|
718
|
+
return dates;
|
|
719
|
+
}
|
|
720
|
+
function dateDiffDays(start, end) {
|
|
721
|
+
const [sy, sm, sd] = parseDateStr(start);
|
|
722
|
+
const [ey, em, ed] = parseDateStr(end);
|
|
723
|
+
const startMs = Date.UTC(sy, sm - 1, sd);
|
|
724
|
+
const endMs = Date.UTC(ey, em - 1, ed);
|
|
725
|
+
return Math.max(0, Math.floor((endMs - startMs) / 864e5));
|
|
726
|
+
}
|
|
727
|
+
function formatDate(d) {
|
|
728
|
+
const y = d.getUTCFullYear();
|
|
729
|
+
const m = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
730
|
+
const day = String(d.getUTCDate()).padStart(2, "0");
|
|
731
|
+
return `${y}-${m}-${day}`;
|
|
732
|
+
}
|
|
733
|
+
function minutesToTime(totalMinutes) {
|
|
734
|
+
const hours = Math.floor(totalMinutes / 60) % 24;
|
|
735
|
+
const minutes = totalMinutes % 60;
|
|
736
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
737
|
+
}
|
|
738
|
+
|
|
478
739
|
// src/services/categories.ts
|
|
479
740
|
var CategoriesService = class extends BaseService {
|
|
480
741
|
constructor() {
|
|
@@ -613,6 +874,135 @@ var PropertiesService = class extends BaseService {
|
|
|
613
874
|
}
|
|
614
875
|
};
|
|
615
876
|
|
|
877
|
+
// src/services/spaces.ts
|
|
878
|
+
var SpacesService = class extends BaseService {
|
|
879
|
+
constructor() {
|
|
880
|
+
super(...arguments);
|
|
881
|
+
this.basePath = "/inventory/v1/spaces";
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Create a new space.
|
|
885
|
+
*
|
|
886
|
+
* @example
|
|
887
|
+
* ```typescript
|
|
888
|
+
* const space = await booking.spaces.create({
|
|
889
|
+
* propertyId: "prop_abc123",
|
|
890
|
+
* name: "Room 101",
|
|
891
|
+
* type: "room",
|
|
892
|
+
* floor: "1",
|
|
893
|
+
* capacity: 2,
|
|
894
|
+
* });
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
create(input) {
|
|
898
|
+
return this._post(this.basePath, input);
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* List spaces for a property with optional filters and cursor-based pagination.
|
|
902
|
+
*
|
|
903
|
+
* @param params - Must include `propertyId`; supports optional `type`, `status`, `categoryId`, `floor` filters
|
|
904
|
+
*
|
|
905
|
+
* @example
|
|
906
|
+
* ```typescript
|
|
907
|
+
* const page = await booking.spaces.list({
|
|
908
|
+
* propertyId: "prop_abc123",
|
|
909
|
+
* type: "room",
|
|
910
|
+
* status: "available",
|
|
911
|
+
* limit: 20,
|
|
912
|
+
* });
|
|
913
|
+
* ```
|
|
914
|
+
*/
|
|
915
|
+
list(params) {
|
|
916
|
+
return this._list(params);
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Get a single space by ID.
|
|
920
|
+
*
|
|
921
|
+
* @example
|
|
922
|
+
* ```typescript
|
|
923
|
+
* const space = await booking.spaces.get("spc_abc123");
|
|
924
|
+
* ```
|
|
925
|
+
*/
|
|
926
|
+
get(spaceId) {
|
|
927
|
+
return this._get(this._buildPath(spaceId));
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Update an existing space.
|
|
931
|
+
*
|
|
932
|
+
* @example
|
|
933
|
+
* ```typescript
|
|
934
|
+
* const updated = await booking.spaces.update("spc_abc123", {
|
|
935
|
+
* name: "Room 101 Deluxe",
|
|
936
|
+
* capacity: 3,
|
|
937
|
+
* });
|
|
938
|
+
* ```
|
|
939
|
+
*/
|
|
940
|
+
update(spaceId, input) {
|
|
941
|
+
return this._patch(this._buildPath(spaceId), input);
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Delete a space.
|
|
945
|
+
*
|
|
946
|
+
* @example
|
|
947
|
+
* ```typescript
|
|
948
|
+
* await booking.spaces.delete("spc_abc123");
|
|
949
|
+
* ```
|
|
950
|
+
*/
|
|
951
|
+
delete(spaceId) {
|
|
952
|
+
return this._delete(this._buildPath(spaceId));
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Bulk create multiple spaces for a property in a single API call.
|
|
956
|
+
*
|
|
957
|
+
* @example
|
|
958
|
+
* ```typescript
|
|
959
|
+
* const spaces = await booking.spaces.bulkCreate("prop_abc123", [
|
|
960
|
+
* { propertyId: "prop_abc123", name: "Room 101", type: "room" },
|
|
961
|
+
* { propertyId: "prop_abc123", name: "Room 102", type: "room" },
|
|
962
|
+
* ]);
|
|
963
|
+
* ```
|
|
964
|
+
*/
|
|
965
|
+
bulkCreate(propertyId, spaces) {
|
|
966
|
+
return this._post(this._buildPath("bulk"), {
|
|
967
|
+
propertyId,
|
|
968
|
+
spaces
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Bulk update multiple spaces for a property in a single API call.
|
|
973
|
+
*
|
|
974
|
+
* @example
|
|
975
|
+
* ```typescript
|
|
976
|
+
* const updated = await booking.spaces.bulkUpdate("prop_abc123", [
|
|
977
|
+
* { id: "spc_1", name: "Room 101 Deluxe" },
|
|
978
|
+
* { id: "spc_2", capacity: 3 },
|
|
979
|
+
* ]);
|
|
980
|
+
* ```
|
|
981
|
+
*/
|
|
982
|
+
bulkUpdate(propertyId, updates) {
|
|
983
|
+
return this._patch(this._buildPath("bulk"), {
|
|
984
|
+
propertyId,
|
|
985
|
+
updates
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Link a space to a POS table. Tables vertical only.
|
|
990
|
+
*
|
|
991
|
+
* Creates a cross-domain bridge between the inventory service and the POS system,
|
|
992
|
+
* enabling a space to reference its physical POS table.
|
|
993
|
+
*
|
|
994
|
+
* @example
|
|
995
|
+
* ```typescript
|
|
996
|
+
* const linked = await booking.spaces.linkPosTable("spc_abc123", {
|
|
997
|
+
* posTableId: "pos_table_42",
|
|
998
|
+
* });
|
|
999
|
+
* ```
|
|
1000
|
+
*/
|
|
1001
|
+
linkPosTable(spaceId, input) {
|
|
1002
|
+
return this._post(this._buildPath(spaceId, "pos-table"), input);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
|
|
616
1006
|
// src/client.ts
|
|
617
1007
|
var BookingClient = class {
|
|
618
1008
|
constructor(config) {
|
|
@@ -630,6 +1020,11 @@ var BookingClient = class {
|
|
|
630
1020
|
logger: validated.logger
|
|
631
1021
|
});
|
|
632
1022
|
}
|
|
1023
|
+
/** Availability service — lazy-initialized on first access */
|
|
1024
|
+
get availability() {
|
|
1025
|
+
this._availability ?? (this._availability = new AvailabilityService(this.httpClient));
|
|
1026
|
+
return this._availability;
|
|
1027
|
+
}
|
|
633
1028
|
/** Properties service — lazy-initialized on first access */
|
|
634
1029
|
get properties() {
|
|
635
1030
|
this._properties ?? (this._properties = new PropertiesService(this.httpClient));
|
|
@@ -640,6 +1035,11 @@ var BookingClient = class {
|
|
|
640
1035
|
this._categories ?? (this._categories = new CategoriesService(this.httpClient));
|
|
641
1036
|
return this._categories;
|
|
642
1037
|
}
|
|
1038
|
+
/** Spaces service — lazy-initialized on first access */
|
|
1039
|
+
get spaces() {
|
|
1040
|
+
this._spaces ?? (this._spaces = new SpacesService(this.httpClient));
|
|
1041
|
+
return this._spaces;
|
|
1042
|
+
}
|
|
643
1043
|
setApiKey(key) {
|
|
644
1044
|
if (!key || key.trim().length === 0) {
|
|
645
1045
|
throw new Error("apiKey must be a non-empty string");
|
|
@@ -703,10 +1103,31 @@ var DEFAULT_MODULES = {
|
|
|
703
1103
|
pos: false
|
|
704
1104
|
};
|
|
705
1105
|
|
|
1106
|
+
// src/types/spaces.ts
|
|
1107
|
+
var SPACE_TYPES = [
|
|
1108
|
+
"room",
|
|
1109
|
+
"table",
|
|
1110
|
+
"sunbed",
|
|
1111
|
+
"parking",
|
|
1112
|
+
"desk",
|
|
1113
|
+
"meeting_room",
|
|
1114
|
+
"locker",
|
|
1115
|
+
"service",
|
|
1116
|
+
"custom"
|
|
1117
|
+
];
|
|
1118
|
+
var SPACE_STATUSES = [
|
|
1119
|
+
"available",
|
|
1120
|
+
"occupied",
|
|
1121
|
+
"maintenance",
|
|
1122
|
+
"blocked",
|
|
1123
|
+
"inactive"
|
|
1124
|
+
];
|
|
1125
|
+
|
|
706
1126
|
// src/index.ts
|
|
707
1127
|
var VERSION = "0.1.0";
|
|
708
1128
|
export {
|
|
709
1129
|
AuthenticationError,
|
|
1130
|
+
AvailabilityService,
|
|
710
1131
|
BookingClient,
|
|
711
1132
|
BookingError,
|
|
712
1133
|
CategoriesService,
|
|
@@ -719,7 +1140,10 @@ export {
|
|
|
719
1140
|
PaymentError,
|
|
720
1141
|
PropertiesService,
|
|
721
1142
|
RateLimitError,
|
|
1143
|
+
SPACE_STATUSES,
|
|
1144
|
+
SPACE_TYPES,
|
|
722
1145
|
ServerError,
|
|
1146
|
+
SpacesService,
|
|
723
1147
|
TimeoutError,
|
|
724
1148
|
VERSION,
|
|
725
1149
|
ValidationError,
|