order3000 0.9.0 → 0.10.1

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.cjs CHANGED
@@ -215,6 +215,20 @@ class EventsResource extends BaseResource {
215
215
  async get(eventId) {
216
216
  return this.request("GET", `/${eventId}`);
217
217
  }
218
+ /**
219
+ * Get an event by accessor (slug)
220
+ * @param accessor - The event accessor (e.g., 'lunch-menu')
221
+ * @param options - Optional expand options
222
+ * @returns The event with optional schedule, timeSlots, menus, and posters
223
+ */
224
+ async getByAccessor(accessor, options) {
225
+ const queryString = this.buildQueryString(options);
226
+ return this.request("GET", `/${accessor}${queryString}`);
227
+ }
228
+ buildQueryString(options) {
229
+ if (!options?.expand?.length) return "";
230
+ return `?expand=${options.expand.join(",")}`;
231
+ }
218
232
  }
219
233
 
220
234
  class MenusResource extends BaseResource {
@@ -241,6 +255,14 @@ class MenusResource extends BaseResource {
241
255
  const queryString = this.buildQueryString(options);
242
256
  return this.request("GET", `/${accessor}${queryString}`);
243
257
  }
258
+ /**
259
+ * Get all bundles for a menu
260
+ * @param menuIdOrAccessor - The menu UUID or accessor (slug)
261
+ * @returns Array of menu bundles
262
+ */
263
+ async getBundles(menuIdOrAccessor) {
264
+ return this.request("GET", `/${menuIdOrAccessor}/bundles`);
265
+ }
244
266
  buildQueryString(options) {
245
267
  if (!options?.expand?.length) return "";
246
268
  return `?expand=${options.expand.join(",")}`;
@@ -486,6 +508,120 @@ class RealtimeManager {
486
508
  }
487
509
  }
488
510
 
511
+ const ALL_DAYS = [
512
+ "monday",
513
+ "tuesday",
514
+ "wednesday",
515
+ "thursday",
516
+ "friday",
517
+ "saturday",
518
+ "sunday"
519
+ ];
520
+ const RRULE_DAY_MAP = {
521
+ MO: "monday",
522
+ TU: "tuesday",
523
+ WE: "wednesday",
524
+ TH: "thursday",
525
+ FR: "friday",
526
+ SA: "saturday",
527
+ SU: "sunday"
528
+ };
529
+ function parseDaysFromRRule(rrule) {
530
+ if (!rrule) {
531
+ return [];
532
+ }
533
+ const byDayMatch = rrule.match(/BYDAY=([^;]+)/);
534
+ if (!byDayMatch) {
535
+ return [];
536
+ }
537
+ const rruleDays = byDayMatch[1].split(",");
538
+ const days = [];
539
+ for (const rruleDay of rruleDays) {
540
+ const day = RRULE_DAY_MAP[rruleDay.trim()];
541
+ if (day) {
542
+ days.push(day);
543
+ }
544
+ }
545
+ return ALL_DAYS.filter((day) => days.includes(day));
546
+ }
547
+ function addMinutesToTime(time, minutes) {
548
+ const parts = time.split(":");
549
+ const hours = parseInt(parts[0], 10);
550
+ const mins = parseInt(parts[1], 10);
551
+ const totalMinutes = hours * 60 + mins + minutes;
552
+ const newHours = Math.floor(totalMinutes / 60) % 24;
553
+ const newMins = totalMinutes % 60;
554
+ return `${newHours.toString().padStart(2, "0")}:${newMins.toString().padStart(2, "0")}`;
555
+ }
556
+ function formatTime(time) {
557
+ const parts = time.split(":");
558
+ if (parts.length >= 2) {
559
+ return `${parts[0]}:${parts[1]}`;
560
+ }
561
+ return time;
562
+ }
563
+ function getScheduleInfo(schedule) {
564
+ const defaultData = {
565
+ timeRange: null,
566
+ activeDays: []
567
+ };
568
+ if (!schedule?.scheduleTimeSlots?.length) {
569
+ return defaultData;
570
+ }
571
+ const timeSlots = schedule.scheduleTimeSlots;
572
+ const rrule = schedule.rrule;
573
+ const intervalMinutes = schedule.intervalMinutes ?? 30;
574
+ const activeDaysSet = /* @__PURE__ */ new Set();
575
+ let hasNullDayOfWeek = false;
576
+ const startTimes = [];
577
+ let latestEndTime = null;
578
+ for (const slot of timeSlots) {
579
+ if (slot.dayOfWeek) {
580
+ activeDaysSet.add(slot.dayOfWeek);
581
+ } else {
582
+ hasNullDayOfWeek = true;
583
+ }
584
+ if (slot.timeSlot.startTime) {
585
+ startTimes.push(slot.timeSlot.startTime);
586
+ }
587
+ if (slot.timeSlot.endTime) {
588
+ if (!latestEndTime || slot.timeSlot.endTime > latestEndTime) {
589
+ latestEndTime = slot.timeSlot.endTime;
590
+ }
591
+ }
592
+ }
593
+ let activeDays;
594
+ if (hasNullDayOfWeek) {
595
+ const rruleDays = parseDaysFromRRule(rrule);
596
+ if (rruleDays.length > 0) {
597
+ activeDays = rruleDays;
598
+ } else {
599
+ activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
600
+ }
601
+ } else {
602
+ activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
603
+ }
604
+ let timeRange = null;
605
+ if (startTimes.length > 0) {
606
+ startTimes.sort();
607
+ const earliestStart = startTimes[0];
608
+ const latestStart = startTimes[startTimes.length - 1];
609
+ let endTime;
610
+ if (latestEndTime) {
611
+ endTime = latestEndTime;
612
+ } else {
613
+ endTime = addMinutesToTime(latestStart, intervalMinutes);
614
+ }
615
+ const startFormatted = formatTime(earliestStart);
616
+ const endFormatted = formatTime(endTime);
617
+ timeRange = `${startFormatted}-${endFormatted}`;
618
+ }
619
+ return {
620
+ timeRange,
621
+ activeDays
622
+ };
623
+ }
624
+
489
625
  var __defProp = Object.defineProperty;
490
626
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
491
627
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -520,3 +656,4 @@ class Order3000Client {
520
656
  }
521
657
 
522
658
  exports.Order3000Client = Order3000Client;
659
+ exports.getScheduleInfo = getScheduleInfo;
package/dist/client.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CurrencyCode } from '@kolaveri/money';
1
2
  import { RealtimePostgresChangesPayload, RealtimeChannel, SupabaseClient } from '@supabase/supabase-js';
2
3
 
3
4
  declare class TokenManager {
@@ -27,6 +28,80 @@ declare abstract class BaseResource {
27
28
 
28
29
  interface components {
29
30
  schemas: {
31
+ /**
32
+ * CreateEventRequest
33
+ * @description Request payload for creating a new event
34
+ */
35
+ CreateEventRequest: {
36
+ accessor?: string | null;
37
+ name: (string | number | boolean | (null)) | {
38
+ [key: string]: unknown;
39
+ } | unknown[];
40
+ description?: ((string | number | boolean | (null)) | {
41
+ [key: string]: unknown;
42
+ } | unknown[]) | null;
43
+ scheduleId?: string | null;
44
+ maxBookings?: number | null;
45
+ maxGuests?: number | null;
46
+ minPartySize?: number | null;
47
+ maxPartySize?: number | null;
48
+ isPublic?: boolean;
49
+ isRecurring?: boolean;
50
+ acceptsReservations?: boolean;
51
+ bookingOpensAtDays?: number | null;
52
+ bookingClosesAtHours?: number | null;
53
+ isActive?: boolean;
54
+ isFeatured?: boolean;
55
+ priority?: number;
56
+ schedule?: {
57
+ rrule?: string | null;
58
+ timezone?: string | null;
59
+ validFrom?: string | null;
60
+ validTo?: string | null;
61
+ timeRanges: {
62
+ startTime: string;
63
+ endTime: string;
64
+ lastSeatingTime?: string | null;
65
+ }[];
66
+ /** @enum {string|null} */
67
+ slotMode?: "interval" | "duration" | null;
68
+ intervalMinutes?: number | null;
69
+ durationMinutes?: number | null;
70
+ } | null;
71
+ venueAccessor: string;
72
+ };
73
+ /**
74
+ * CreateEventResponse
75
+ * @description Successfully created event
76
+ */
77
+ CreateEventResponse: {
78
+ id: string;
79
+ venueId: string;
80
+ accessor: string | null;
81
+ name: (string | number | boolean | (null)) | {
82
+ [key: string]: unknown;
83
+ } | unknown[];
84
+ description: ((string | number | boolean | (null)) | {
85
+ [key: string]: unknown;
86
+ } | unknown[]) | null;
87
+ scheduleId: string | null;
88
+ maxBookings: number | null;
89
+ maxGuests: number | null;
90
+ minPartySize: number | null;
91
+ maxPartySize: number | null;
92
+ isPublic: boolean;
93
+ isRecurring: boolean;
94
+ acceptsReservations: boolean;
95
+ bookingOpensAtDays: number | null;
96
+ bookingClosesAtHours: number | null;
97
+ isActive: boolean;
98
+ isFeatured: boolean;
99
+ priority: number;
100
+ createdBy: string | null;
101
+ updatedBy: string | null;
102
+ createdAt: unknown;
103
+ updatedAt: unknown;
104
+ };
30
105
  /**
31
106
  * PlaceOrderRequest
32
107
  * @description Place a new order for a specific venue
@@ -116,6 +191,7 @@ interface components {
116
191
  specialRequests: string | null;
117
192
  /** @description Preferred seating area or table type (e.g., "window seat", "quiet area", "patio") */
118
193
  tablePreference: string | null;
194
+ venueAccessor: string;
119
195
  };
120
196
  /**
121
197
  * MakeReservationResponse
@@ -205,79 +281,6 @@ interface components {
205
281
  /** @description Last update timestamp */
206
282
  updatedAt: unknown;
207
283
  };
208
- /**
209
- * CreateEventRequest
210
- * @description Request payload for creating a new event
211
- */
212
- CreateEventRequest: {
213
- accessor?: string | null;
214
- name: (string | number | boolean | (null)) | {
215
- [key: string]: unknown;
216
- } | unknown[];
217
- description?: ((string | number | boolean | (null)) | {
218
- [key: string]: unknown;
219
- } | unknown[]) | null;
220
- scheduleId?: string | null;
221
- maxBookings?: number | null;
222
- maxGuests?: number | null;
223
- minPartySize?: number | null;
224
- maxPartySize?: number | null;
225
- isPublic?: boolean;
226
- isRecurring?: boolean;
227
- acceptsReservations?: boolean;
228
- bookingOpensAtDays?: number | null;
229
- bookingClosesAtHours?: number | null;
230
- isActive?: boolean;
231
- isFeatured?: boolean;
232
- priority?: number;
233
- schedule?: {
234
- rrule?: string | null;
235
- timezone?: string | null;
236
- validFrom?: string | null;
237
- validTo?: string | null;
238
- timeRanges: {
239
- startTime: string;
240
- endTime: string;
241
- lastSeatingTime?: string | null;
242
- }[];
243
- /** @enum {string|null} */
244
- slotMode?: "interval" | "duration" | null;
245
- intervalMinutes?: number | null;
246
- durationMinutes?: number | null;
247
- } | null;
248
- };
249
- /**
250
- * CreateEventResponse
251
- * @description Successfully created event
252
- */
253
- CreateEventResponse: {
254
- id: string;
255
- venueId: string;
256
- accessor: string | null;
257
- name: (string | number | boolean | (null)) | {
258
- [key: string]: unknown;
259
- } | unknown[];
260
- description: ((string | number | boolean | (null)) | {
261
- [key: string]: unknown;
262
- } | unknown[]) | null;
263
- scheduleId: string | null;
264
- maxBookings: number | null;
265
- maxGuests: number | null;
266
- minPartySize: number | null;
267
- maxPartySize: number | null;
268
- isPublic: boolean;
269
- isRecurring: boolean;
270
- acceptsReservations: boolean;
271
- bookingOpensAtDays: number | null;
272
- bookingClosesAtHours: number | null;
273
- isActive: boolean;
274
- isFeatured: boolean;
275
- priority: number;
276
- createdBy: string | null;
277
- updatedBy: string | null;
278
- createdAt: unknown;
279
- updatedAt: unknown;
280
- };
281
284
  };
282
285
  responses: never;
283
286
  parameters: never;
@@ -293,11 +296,12 @@ type PlaceOrderRequest = schemas['PlaceOrderRequest'];
293
296
  type PlaceOrderResponse = schemas['PlaceOrderResponse'];
294
297
  type MakeReservationRequest = schemas['MakeReservationRequest'];
295
298
  type MakeReservationResponse = schemas['MakeReservationResponse'];
299
+ type DayOfWeek = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
296
300
  interface TimeSlot {
297
301
  id: string;
298
302
  startTime: string;
299
303
  endTime: string | null;
300
- dayOfWeek?: 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT' | 'SUN' | null;
304
+ dayOfWeek?: DayOfWeek | null;
301
305
  isSchedulable: boolean | null;
302
306
  }
303
307
  interface ScheduleOverride {
@@ -457,7 +461,8 @@ interface MenuItem {
457
461
  id: string;
458
462
  type: MenuItemType;
459
463
  tags: string[] | null;
460
- price: number;
464
+ /** Price adjustment in cents (adds to bundle base price) */
465
+ priceAdjustment: number;
461
466
  currency: string;
462
467
  isActive: boolean;
463
468
  sortIndex: string | null;
@@ -476,6 +481,72 @@ interface GetMenuOptions {
476
481
  /** Expand related resources (items, assets) */
477
482
  expand?: ('items' | 'assets')[];
478
483
  }
484
+ interface MenuBundleDeposit {
485
+ name: Record<string, string>;
486
+ amount: number;
487
+ currency: CurrencyCode;
488
+ }
489
+ interface MenuBundle {
490
+ id: string;
491
+ menuId: string;
492
+ name: Record<string, string>;
493
+ description: Record<string, string> | null;
494
+ tags: string[];
495
+ price: number;
496
+ currency: CurrencyCode;
497
+ taxRateId: string;
498
+ isActive: boolean;
499
+ sortIndex: string | null;
500
+ deposit: MenuBundleDeposit | null;
501
+ }
502
+ interface ScheduleTimeSlot {
503
+ dayOfWeek: DayOfWeek | null;
504
+ timeSlot: {
505
+ id: string;
506
+ startTime: string;
507
+ endTime: string | null;
508
+ isActive: boolean | null;
509
+ isSchedulable: boolean | null;
510
+ };
511
+ }
512
+ interface ScheduleWithTimeSlots extends Schedule {
513
+ scheduleTimeSlots?: ScheduleTimeSlot[];
514
+ }
515
+ interface EventMenu {
516
+ id: string;
517
+ accessor: string;
518
+ name: Record<string, string>;
519
+ category: string;
520
+ }
521
+ interface EventByAccessor {
522
+ id: string;
523
+ venueId: string;
524
+ accessor: string | null;
525
+ name: Record<string, string>;
526
+ description: Record<string, string> | null;
527
+ scheduleId: string | null;
528
+ maxBookings: number | null;
529
+ maxGuests: number | null;
530
+ minPartySize: number | null;
531
+ maxPartySize: number | null;
532
+ isPublic: boolean;
533
+ isRecurring: boolean;
534
+ acceptsReservations: boolean;
535
+ bookingOpensAtDays: number | null;
536
+ bookingClosesAtHours: number | null;
537
+ isActive: boolean;
538
+ isFeatured: boolean;
539
+ priority: number;
540
+ createdAt: string | null;
541
+ updatedAt: string | null;
542
+ schedule?: ScheduleWithTimeSlots;
543
+ menus?: EventMenu[];
544
+ posters?: EventPoster[];
545
+ }
546
+ interface GetEventOptions {
547
+ /** Expand related resources (schedule, timeSlots, menus, posters) */
548
+ expand?: ('schedule' | 'timeSlots' | 'menus' | 'posters')[];
549
+ }
479
550
  type BasketStatus = 'active' | 'abandoned' | 'converted';
480
551
  type Currency = 'EUR' | 'CHF';
481
552
  /**
@@ -601,6 +672,14 @@ declare class EventsResource extends BaseResource {
601
672
  * @returns The event details
602
673
  */
603
674
  get(eventId: string): Promise<Event>;
675
+ /**
676
+ * Get an event by accessor (slug)
677
+ * @param accessor - The event accessor (e.g., 'lunch-menu')
678
+ * @param options - Optional expand options
679
+ * @returns The event with optional schedule, timeSlots, menus, and posters
680
+ */
681
+ getByAccessor(accessor: string, options?: GetEventOptions): Promise<EventByAccessor>;
682
+ private buildQueryString;
604
683
  }
605
684
 
606
685
  declare class MenusResource extends BaseResource {
@@ -619,6 +698,12 @@ declare class MenusResource extends BaseResource {
619
698
  * @returns The menu with optional items and assets
620
699
  */
621
700
  getByAccessor(accessor: string, options?: GetMenuOptions): Promise<Menu>;
701
+ /**
702
+ * Get all bundles for a menu
703
+ * @param menuIdOrAccessor - The menu UUID or accessor (slug)
704
+ * @returns Array of menu bundles
705
+ */
706
+ getBundles(menuIdOrAccessor: string): Promise<MenuBundle[]>;
622
707
  private buildQueryString;
623
708
  }
624
709
 
@@ -668,7 +753,7 @@ interface MenuItemRow {
668
753
  type: 'dish' | 'beverage';
669
754
  dish_id: string | null;
670
755
  beverage_id: string | null;
671
- price: number;
756
+ price_adjustment: number;
672
757
  currency: string;
673
758
  is_active: boolean;
674
759
  tags: string[] | null;
@@ -765,6 +850,26 @@ declare class RealtimeManager {
765
850
  disconnectAll(): Promise<void>;
766
851
  }
767
852
 
853
+ interface ScheduleInfo {
854
+ /** Time range string, e.g. "11:30-15:00" */
855
+ timeRange: string | null;
856
+ /** Active days in week order */
857
+ activeDays: DayOfWeek[];
858
+ }
859
+ interface ScheduleInput {
860
+ rrule?: string | null;
861
+ intervalMinutes?: number | null;
862
+ scheduleTimeSlots?: ScheduleTimeSlot[];
863
+ }
864
+ /**
865
+ * Extract schedule information from a schedule object.
866
+ * Returns time range and active days for display purposes.
867
+ *
868
+ * @param schedule - Schedule object with rrule, intervalMinutes, and scheduleTimeSlots
869
+ * @returns ScheduleInfo with timeRange and activeDays
870
+ */
871
+ declare function getScheduleInfo(schedule: ScheduleInput | null | undefined): ScheduleInfo;
872
+
768
873
  interface Order3000ClientConfig {
769
874
  clientId: string;
770
875
  clientSecret: string;
@@ -792,4 +897,4 @@ declare class Order3000Client {
792
897
  constructor(config: Order3000ClientConfig);
793
898
  }
794
899
 
795
- export { type AddToBasketRequest, type AddToBasketResponse, type Basket, type BasketItem, type BasketItemMenuItemRef, type BasketItemMetadata, type BasketStatus, type CropArea, type Currency, type Event, type EventPoster, type EventRow, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type RemoveFromBasketResponse, type Schedule, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type SubscriptionOptions, type TimeSlot, type Unit };
900
+ export { type AddToBasketRequest, type AddToBasketResponse, type Basket, type BasketItem, type BasketItemMenuItemRef, type BasketItemMetadata, type BasketStatus, type CropArea, type Currency, type DayOfWeek, type Event, type EventByAccessor, type EventMenu, type EventPoster, type EventRow, type GetEventOptions, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuBundle, type MenuBundleDeposit, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type RemoveFromBasketResponse, type Schedule, type ScheduleInfo, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type ScheduleTimeSlot, type ScheduleWithTimeSlots, type SubscriptionOptions, type TimeSlot, type Unit, getScheduleInfo };
package/dist/client.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CurrencyCode } from '@kolaveri/money';
1
2
  import { RealtimePostgresChangesPayload, RealtimeChannel, SupabaseClient } from '@supabase/supabase-js';
2
3
 
3
4
  declare class TokenManager {
@@ -27,6 +28,80 @@ declare abstract class BaseResource {
27
28
 
28
29
  interface components {
29
30
  schemas: {
31
+ /**
32
+ * CreateEventRequest
33
+ * @description Request payload for creating a new event
34
+ */
35
+ CreateEventRequest: {
36
+ accessor?: string | null;
37
+ name: (string | number | boolean | (null)) | {
38
+ [key: string]: unknown;
39
+ } | unknown[];
40
+ description?: ((string | number | boolean | (null)) | {
41
+ [key: string]: unknown;
42
+ } | unknown[]) | null;
43
+ scheduleId?: string | null;
44
+ maxBookings?: number | null;
45
+ maxGuests?: number | null;
46
+ minPartySize?: number | null;
47
+ maxPartySize?: number | null;
48
+ isPublic?: boolean;
49
+ isRecurring?: boolean;
50
+ acceptsReservations?: boolean;
51
+ bookingOpensAtDays?: number | null;
52
+ bookingClosesAtHours?: number | null;
53
+ isActive?: boolean;
54
+ isFeatured?: boolean;
55
+ priority?: number;
56
+ schedule?: {
57
+ rrule?: string | null;
58
+ timezone?: string | null;
59
+ validFrom?: string | null;
60
+ validTo?: string | null;
61
+ timeRanges: {
62
+ startTime: string;
63
+ endTime: string;
64
+ lastSeatingTime?: string | null;
65
+ }[];
66
+ /** @enum {string|null} */
67
+ slotMode?: "interval" | "duration" | null;
68
+ intervalMinutes?: number | null;
69
+ durationMinutes?: number | null;
70
+ } | null;
71
+ venueAccessor: string;
72
+ };
73
+ /**
74
+ * CreateEventResponse
75
+ * @description Successfully created event
76
+ */
77
+ CreateEventResponse: {
78
+ id: string;
79
+ venueId: string;
80
+ accessor: string | null;
81
+ name: (string | number | boolean | (null)) | {
82
+ [key: string]: unknown;
83
+ } | unknown[];
84
+ description: ((string | number | boolean | (null)) | {
85
+ [key: string]: unknown;
86
+ } | unknown[]) | null;
87
+ scheduleId: string | null;
88
+ maxBookings: number | null;
89
+ maxGuests: number | null;
90
+ minPartySize: number | null;
91
+ maxPartySize: number | null;
92
+ isPublic: boolean;
93
+ isRecurring: boolean;
94
+ acceptsReservations: boolean;
95
+ bookingOpensAtDays: number | null;
96
+ bookingClosesAtHours: number | null;
97
+ isActive: boolean;
98
+ isFeatured: boolean;
99
+ priority: number;
100
+ createdBy: string | null;
101
+ updatedBy: string | null;
102
+ createdAt: unknown;
103
+ updatedAt: unknown;
104
+ };
30
105
  /**
31
106
  * PlaceOrderRequest
32
107
  * @description Place a new order for a specific venue
@@ -116,6 +191,7 @@ interface components {
116
191
  specialRequests: string | null;
117
192
  /** @description Preferred seating area or table type (e.g., "window seat", "quiet area", "patio") */
118
193
  tablePreference: string | null;
194
+ venueAccessor: string;
119
195
  };
120
196
  /**
121
197
  * MakeReservationResponse
@@ -205,79 +281,6 @@ interface components {
205
281
  /** @description Last update timestamp */
206
282
  updatedAt: unknown;
207
283
  };
208
- /**
209
- * CreateEventRequest
210
- * @description Request payload for creating a new event
211
- */
212
- CreateEventRequest: {
213
- accessor?: string | null;
214
- name: (string | number | boolean | (null)) | {
215
- [key: string]: unknown;
216
- } | unknown[];
217
- description?: ((string | number | boolean | (null)) | {
218
- [key: string]: unknown;
219
- } | unknown[]) | null;
220
- scheduleId?: string | null;
221
- maxBookings?: number | null;
222
- maxGuests?: number | null;
223
- minPartySize?: number | null;
224
- maxPartySize?: number | null;
225
- isPublic?: boolean;
226
- isRecurring?: boolean;
227
- acceptsReservations?: boolean;
228
- bookingOpensAtDays?: number | null;
229
- bookingClosesAtHours?: number | null;
230
- isActive?: boolean;
231
- isFeatured?: boolean;
232
- priority?: number;
233
- schedule?: {
234
- rrule?: string | null;
235
- timezone?: string | null;
236
- validFrom?: string | null;
237
- validTo?: string | null;
238
- timeRanges: {
239
- startTime: string;
240
- endTime: string;
241
- lastSeatingTime?: string | null;
242
- }[];
243
- /** @enum {string|null} */
244
- slotMode?: "interval" | "duration" | null;
245
- intervalMinutes?: number | null;
246
- durationMinutes?: number | null;
247
- } | null;
248
- };
249
- /**
250
- * CreateEventResponse
251
- * @description Successfully created event
252
- */
253
- CreateEventResponse: {
254
- id: string;
255
- venueId: string;
256
- accessor: string | null;
257
- name: (string | number | boolean | (null)) | {
258
- [key: string]: unknown;
259
- } | unknown[];
260
- description: ((string | number | boolean | (null)) | {
261
- [key: string]: unknown;
262
- } | unknown[]) | null;
263
- scheduleId: string | null;
264
- maxBookings: number | null;
265
- maxGuests: number | null;
266
- minPartySize: number | null;
267
- maxPartySize: number | null;
268
- isPublic: boolean;
269
- isRecurring: boolean;
270
- acceptsReservations: boolean;
271
- bookingOpensAtDays: number | null;
272
- bookingClosesAtHours: number | null;
273
- isActive: boolean;
274
- isFeatured: boolean;
275
- priority: number;
276
- createdBy: string | null;
277
- updatedBy: string | null;
278
- createdAt: unknown;
279
- updatedAt: unknown;
280
- };
281
284
  };
282
285
  responses: never;
283
286
  parameters: never;
@@ -293,11 +296,12 @@ type PlaceOrderRequest = schemas['PlaceOrderRequest'];
293
296
  type PlaceOrderResponse = schemas['PlaceOrderResponse'];
294
297
  type MakeReservationRequest = schemas['MakeReservationRequest'];
295
298
  type MakeReservationResponse = schemas['MakeReservationResponse'];
299
+ type DayOfWeek = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
296
300
  interface TimeSlot {
297
301
  id: string;
298
302
  startTime: string;
299
303
  endTime: string | null;
300
- dayOfWeek?: 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT' | 'SUN' | null;
304
+ dayOfWeek?: DayOfWeek | null;
301
305
  isSchedulable: boolean | null;
302
306
  }
303
307
  interface ScheduleOverride {
@@ -457,7 +461,8 @@ interface MenuItem {
457
461
  id: string;
458
462
  type: MenuItemType;
459
463
  tags: string[] | null;
460
- price: number;
464
+ /** Price adjustment in cents (adds to bundle base price) */
465
+ priceAdjustment: number;
461
466
  currency: string;
462
467
  isActive: boolean;
463
468
  sortIndex: string | null;
@@ -476,6 +481,72 @@ interface GetMenuOptions {
476
481
  /** Expand related resources (items, assets) */
477
482
  expand?: ('items' | 'assets')[];
478
483
  }
484
+ interface MenuBundleDeposit {
485
+ name: Record<string, string>;
486
+ amount: number;
487
+ currency: CurrencyCode;
488
+ }
489
+ interface MenuBundle {
490
+ id: string;
491
+ menuId: string;
492
+ name: Record<string, string>;
493
+ description: Record<string, string> | null;
494
+ tags: string[];
495
+ price: number;
496
+ currency: CurrencyCode;
497
+ taxRateId: string;
498
+ isActive: boolean;
499
+ sortIndex: string | null;
500
+ deposit: MenuBundleDeposit | null;
501
+ }
502
+ interface ScheduleTimeSlot {
503
+ dayOfWeek: DayOfWeek | null;
504
+ timeSlot: {
505
+ id: string;
506
+ startTime: string;
507
+ endTime: string | null;
508
+ isActive: boolean | null;
509
+ isSchedulable: boolean | null;
510
+ };
511
+ }
512
+ interface ScheduleWithTimeSlots extends Schedule {
513
+ scheduleTimeSlots?: ScheduleTimeSlot[];
514
+ }
515
+ interface EventMenu {
516
+ id: string;
517
+ accessor: string;
518
+ name: Record<string, string>;
519
+ category: string;
520
+ }
521
+ interface EventByAccessor {
522
+ id: string;
523
+ venueId: string;
524
+ accessor: string | null;
525
+ name: Record<string, string>;
526
+ description: Record<string, string> | null;
527
+ scheduleId: string | null;
528
+ maxBookings: number | null;
529
+ maxGuests: number | null;
530
+ minPartySize: number | null;
531
+ maxPartySize: number | null;
532
+ isPublic: boolean;
533
+ isRecurring: boolean;
534
+ acceptsReservations: boolean;
535
+ bookingOpensAtDays: number | null;
536
+ bookingClosesAtHours: number | null;
537
+ isActive: boolean;
538
+ isFeatured: boolean;
539
+ priority: number;
540
+ createdAt: string | null;
541
+ updatedAt: string | null;
542
+ schedule?: ScheduleWithTimeSlots;
543
+ menus?: EventMenu[];
544
+ posters?: EventPoster[];
545
+ }
546
+ interface GetEventOptions {
547
+ /** Expand related resources (schedule, timeSlots, menus, posters) */
548
+ expand?: ('schedule' | 'timeSlots' | 'menus' | 'posters')[];
549
+ }
479
550
  type BasketStatus = 'active' | 'abandoned' | 'converted';
480
551
  type Currency = 'EUR' | 'CHF';
481
552
  /**
@@ -601,6 +672,14 @@ declare class EventsResource extends BaseResource {
601
672
  * @returns The event details
602
673
  */
603
674
  get(eventId: string): Promise<Event>;
675
+ /**
676
+ * Get an event by accessor (slug)
677
+ * @param accessor - The event accessor (e.g., 'lunch-menu')
678
+ * @param options - Optional expand options
679
+ * @returns The event with optional schedule, timeSlots, menus, and posters
680
+ */
681
+ getByAccessor(accessor: string, options?: GetEventOptions): Promise<EventByAccessor>;
682
+ private buildQueryString;
604
683
  }
605
684
 
606
685
  declare class MenusResource extends BaseResource {
@@ -619,6 +698,12 @@ declare class MenusResource extends BaseResource {
619
698
  * @returns The menu with optional items and assets
620
699
  */
621
700
  getByAccessor(accessor: string, options?: GetMenuOptions): Promise<Menu>;
701
+ /**
702
+ * Get all bundles for a menu
703
+ * @param menuIdOrAccessor - The menu UUID or accessor (slug)
704
+ * @returns Array of menu bundles
705
+ */
706
+ getBundles(menuIdOrAccessor: string): Promise<MenuBundle[]>;
622
707
  private buildQueryString;
623
708
  }
624
709
 
@@ -668,7 +753,7 @@ interface MenuItemRow {
668
753
  type: 'dish' | 'beverage';
669
754
  dish_id: string | null;
670
755
  beverage_id: string | null;
671
- price: number;
756
+ price_adjustment: number;
672
757
  currency: string;
673
758
  is_active: boolean;
674
759
  tags: string[] | null;
@@ -765,6 +850,26 @@ declare class RealtimeManager {
765
850
  disconnectAll(): Promise<void>;
766
851
  }
767
852
 
853
+ interface ScheduleInfo {
854
+ /** Time range string, e.g. "11:30-15:00" */
855
+ timeRange: string | null;
856
+ /** Active days in week order */
857
+ activeDays: DayOfWeek[];
858
+ }
859
+ interface ScheduleInput {
860
+ rrule?: string | null;
861
+ intervalMinutes?: number | null;
862
+ scheduleTimeSlots?: ScheduleTimeSlot[];
863
+ }
864
+ /**
865
+ * Extract schedule information from a schedule object.
866
+ * Returns time range and active days for display purposes.
867
+ *
868
+ * @param schedule - Schedule object with rrule, intervalMinutes, and scheduleTimeSlots
869
+ * @returns ScheduleInfo with timeRange and activeDays
870
+ */
871
+ declare function getScheduleInfo(schedule: ScheduleInput | null | undefined): ScheduleInfo;
872
+
768
873
  interface Order3000ClientConfig {
769
874
  clientId: string;
770
875
  clientSecret: string;
@@ -792,4 +897,4 @@ declare class Order3000Client {
792
897
  constructor(config: Order3000ClientConfig);
793
898
  }
794
899
 
795
- export { type AddToBasketRequest, type AddToBasketResponse, type Basket, type BasketItem, type BasketItemMenuItemRef, type BasketItemMetadata, type BasketStatus, type CropArea, type Currency, type Event, type EventPoster, type EventRow, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type RemoveFromBasketResponse, type Schedule, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type SubscriptionOptions, type TimeSlot, type Unit };
900
+ export { type AddToBasketRequest, type AddToBasketResponse, type Basket, type BasketItem, type BasketItemMenuItemRef, type BasketItemMetadata, type BasketStatus, type CropArea, type Currency, type DayOfWeek, type Event, type EventByAccessor, type EventMenu, type EventPoster, type EventRow, type GetEventOptions, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuBundle, type MenuBundleDeposit, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type RemoveFromBasketResponse, type Schedule, type ScheduleInfo, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type ScheduleTimeSlot, type ScheduleWithTimeSlots, type SubscriptionOptions, type TimeSlot, type Unit, getScheduleInfo };
package/dist/client.mjs CHANGED
@@ -213,6 +213,20 @@ class EventsResource extends BaseResource {
213
213
  async get(eventId) {
214
214
  return this.request("GET", `/${eventId}`);
215
215
  }
216
+ /**
217
+ * Get an event by accessor (slug)
218
+ * @param accessor - The event accessor (e.g., 'lunch-menu')
219
+ * @param options - Optional expand options
220
+ * @returns The event with optional schedule, timeSlots, menus, and posters
221
+ */
222
+ async getByAccessor(accessor, options) {
223
+ const queryString = this.buildQueryString(options);
224
+ return this.request("GET", `/${accessor}${queryString}`);
225
+ }
226
+ buildQueryString(options) {
227
+ if (!options?.expand?.length) return "";
228
+ return `?expand=${options.expand.join(",")}`;
229
+ }
216
230
  }
217
231
 
218
232
  class MenusResource extends BaseResource {
@@ -239,6 +253,14 @@ class MenusResource extends BaseResource {
239
253
  const queryString = this.buildQueryString(options);
240
254
  return this.request("GET", `/${accessor}${queryString}`);
241
255
  }
256
+ /**
257
+ * Get all bundles for a menu
258
+ * @param menuIdOrAccessor - The menu UUID or accessor (slug)
259
+ * @returns Array of menu bundles
260
+ */
261
+ async getBundles(menuIdOrAccessor) {
262
+ return this.request("GET", `/${menuIdOrAccessor}/bundles`);
263
+ }
242
264
  buildQueryString(options) {
243
265
  if (!options?.expand?.length) return "";
244
266
  return `?expand=${options.expand.join(",")}`;
@@ -484,6 +506,120 @@ class RealtimeManager {
484
506
  }
485
507
  }
486
508
 
509
+ const ALL_DAYS = [
510
+ "monday",
511
+ "tuesday",
512
+ "wednesday",
513
+ "thursday",
514
+ "friday",
515
+ "saturday",
516
+ "sunday"
517
+ ];
518
+ const RRULE_DAY_MAP = {
519
+ MO: "monday",
520
+ TU: "tuesday",
521
+ WE: "wednesday",
522
+ TH: "thursday",
523
+ FR: "friday",
524
+ SA: "saturday",
525
+ SU: "sunday"
526
+ };
527
+ function parseDaysFromRRule(rrule) {
528
+ if (!rrule) {
529
+ return [];
530
+ }
531
+ const byDayMatch = rrule.match(/BYDAY=([^;]+)/);
532
+ if (!byDayMatch) {
533
+ return [];
534
+ }
535
+ const rruleDays = byDayMatch[1].split(",");
536
+ const days = [];
537
+ for (const rruleDay of rruleDays) {
538
+ const day = RRULE_DAY_MAP[rruleDay.trim()];
539
+ if (day) {
540
+ days.push(day);
541
+ }
542
+ }
543
+ return ALL_DAYS.filter((day) => days.includes(day));
544
+ }
545
+ function addMinutesToTime(time, minutes) {
546
+ const parts = time.split(":");
547
+ const hours = parseInt(parts[0], 10);
548
+ const mins = parseInt(parts[1], 10);
549
+ const totalMinutes = hours * 60 + mins + minutes;
550
+ const newHours = Math.floor(totalMinutes / 60) % 24;
551
+ const newMins = totalMinutes % 60;
552
+ return `${newHours.toString().padStart(2, "0")}:${newMins.toString().padStart(2, "0")}`;
553
+ }
554
+ function formatTime(time) {
555
+ const parts = time.split(":");
556
+ if (parts.length >= 2) {
557
+ return `${parts[0]}:${parts[1]}`;
558
+ }
559
+ return time;
560
+ }
561
+ function getScheduleInfo(schedule) {
562
+ const defaultData = {
563
+ timeRange: null,
564
+ activeDays: []
565
+ };
566
+ if (!schedule?.scheduleTimeSlots?.length) {
567
+ return defaultData;
568
+ }
569
+ const timeSlots = schedule.scheduleTimeSlots;
570
+ const rrule = schedule.rrule;
571
+ const intervalMinutes = schedule.intervalMinutes ?? 30;
572
+ const activeDaysSet = /* @__PURE__ */ new Set();
573
+ let hasNullDayOfWeek = false;
574
+ const startTimes = [];
575
+ let latestEndTime = null;
576
+ for (const slot of timeSlots) {
577
+ if (slot.dayOfWeek) {
578
+ activeDaysSet.add(slot.dayOfWeek);
579
+ } else {
580
+ hasNullDayOfWeek = true;
581
+ }
582
+ if (slot.timeSlot.startTime) {
583
+ startTimes.push(slot.timeSlot.startTime);
584
+ }
585
+ if (slot.timeSlot.endTime) {
586
+ if (!latestEndTime || slot.timeSlot.endTime > latestEndTime) {
587
+ latestEndTime = slot.timeSlot.endTime;
588
+ }
589
+ }
590
+ }
591
+ let activeDays;
592
+ if (hasNullDayOfWeek) {
593
+ const rruleDays = parseDaysFromRRule(rrule);
594
+ if (rruleDays.length > 0) {
595
+ activeDays = rruleDays;
596
+ } else {
597
+ activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
598
+ }
599
+ } else {
600
+ activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
601
+ }
602
+ let timeRange = null;
603
+ if (startTimes.length > 0) {
604
+ startTimes.sort();
605
+ const earliestStart = startTimes[0];
606
+ const latestStart = startTimes[startTimes.length - 1];
607
+ let endTime;
608
+ if (latestEndTime) {
609
+ endTime = latestEndTime;
610
+ } else {
611
+ endTime = addMinutesToTime(latestStart, intervalMinutes);
612
+ }
613
+ const startFormatted = formatTime(earliestStart);
614
+ const endFormatted = formatTime(endTime);
615
+ timeRange = `${startFormatted}-${endFormatted}`;
616
+ }
617
+ return {
618
+ timeRange,
619
+ activeDays
620
+ };
621
+ }
622
+
487
623
  var __defProp = Object.defineProperty;
488
624
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
489
625
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -517,4 +653,4 @@ class Order3000Client {
517
653
  }
518
654
  }
519
655
 
520
- export { Order3000Client };
656
+ export { Order3000Client, getScheduleInfo };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "order3000",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "order3000 node.js sdk",
5
5
  "main": "./dist/client.cjs",
6
6
  "module": "./dist/client.mjs",
@@ -20,7 +20,8 @@
20
20
  "@types/react-type-animation": "^2.0.0",
21
21
  "i18next": "^25.6.0",
22
22
  "i18next-fs-backend": "^2.6.0",
23
- "react-type-animation": "^3.2.0"
23
+ "react-type-animation": "^3.2.0",
24
+ "@kolaveri/money": "1.1.3"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@types/node": "^24.10.0",
@@ -29,9 +30,9 @@
29
30
  "prettier": "^3.7.4",
30
31
  "tsx": "^4.19.2",
31
32
  "typescript": "^5.9.3",
32
- "@kolaveri/eslint-config": "1.0.9",
33
- "@kolaveri/tsconfig": "1.0.1",
34
- "@kolaveri/prettier-config": "1.0.6"
33
+ "@kolaveri/eslint-config": "1.4.0",
34
+ "@kolaveri/prettier-config": "1.0.6",
35
+ "@kolaveri/tsconfig": "1.0.1"
35
36
  },
36
37
  "files": [
37
38
  "dist"