@wix/himalaya-cli 0.1528.0 → 0.1529.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.
Files changed (59) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/ecom/src/extensions.d.ts +144 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/restaurants/src/extensions.d.ts +93 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +27 -5
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +19 -3
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +27 -5
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-ecom.mjs +58 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-restaurants.mjs +23 -0
  8. package/dist/cli.mjs +2425 -1541
  9. package/fixtures/wix-canned.json +83 -0
  10. package/guides/hhp.md +39 -0
  11. package/guides/himi-json-output.md +22 -1
  12. package/package.json +2 -2
  13. package/templates/beauty-salon/config.ts +12 -1
  14. package/templates/beauty-salon/tier5-src/_shared/himi-restaurants.ts +12 -5
  15. package/templates/beauty-salon/tier5-src/_shared/restaurant-ordering.ts +201 -0
  16. package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +6 -0
  17. package/templates/branded-lite/config.ts +12 -1
  18. package/templates/branded-lite/dev/index.ts +1278 -180
  19. package/templates/branded-lite/tier5-src/_shared/himi-restaurants.ts +12 -5
  20. package/templates/branded-lite/tier5-src/_shared/restaurant-ordering.ts +201 -0
  21. package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +6 -0
  22. package/templates/branded-lite/tier5-src/himi-branded-lite-menu-item/index.ts +144 -77
  23. package/templates/branded-lite/tier5-src/himi-branded-lite-menus/index.ts +16 -5
  24. package/templates/branded-lite/tier5-src/himi-branded-lite-reservations/index.ts +1 -1
  25. package/templates/branded-lite/tier5-src/wix-spaces-food-order-detail/index.ts +76 -14
  26. package/templates/branded-lite/tier5-src/wix-spaces-food-orders/index.ts +807 -55
  27. package/templates/community-club/config.ts +12 -1
  28. package/templates/community-club/tier5-src/_shared/himi-restaurants.ts +12 -5
  29. package/templates/events-meetups/config.ts +12 -1
  30. package/templates/events-meetups/tier5-src/_shared/himi-restaurants.ts +12 -5
  31. package/templates/gym-fitness/config.ts +12 -1
  32. package/templates/gym-fitness/tier5-src/_shared/himi-restaurants.ts +12 -5
  33. package/templates/gym-fitness/tier5-src/_shared/restaurant-ordering.ts +201 -0
  34. package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +6 -0
  35. package/templates/nonprofit-cause/config.ts +12 -1
  36. package/templates/nonprofit-cause/tier5-src/_shared/himi-restaurants.ts +12 -5
  37. package/templates/podcast-creator/config.ts +12 -1
  38. package/templates/podcast-creator/tier5-src/_shared/himi-restaurants.ts +12 -5
  39. package/templates/portfolio-creative/config.ts +12 -1
  40. package/templates/portfolio-creative/tier5-src/_shared/himi-restaurants.ts +12 -5
  41. package/templates/portfolio-creative/tier5-src/_shared/restaurant-ordering.ts +201 -0
  42. package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +6 -0
  43. package/templates/restaurant/README.md +1 -1
  44. package/templates/restaurant/config.ts +12 -1
  45. package/templates/restaurant/dev/index.ts +1373 -275
  46. package/templates/restaurant/himalaya.template.json +2 -1
  47. package/templates/restaurant/tier5-src/_shared/himi-restaurants.ts +12 -5
  48. package/templates/restaurant/tier5-src/_shared/member-orders.ts +8 -0
  49. package/templates/restaurant/tier5-src/_shared/restaurant-ordering.ts +201 -0
  50. package/templates/restaurant/tier5-src/himi-branded-lite-menu-item/index.ts +144 -77
  51. package/templates/restaurant/tier5-src/himi-branded-lite-menus/index.ts +16 -5
  52. package/templates/restaurant/tier5-src/wix-spaces-food-order-detail/index.ts +76 -14
  53. package/templates/restaurant/tier5-src/wix-spaces-food-orders/index.ts +807 -55
  54. package/templates/retail-store/config.ts +12 -1
  55. package/templates/retail-store/tier5-src/_shared/himi-restaurants.ts +12 -5
  56. package/templates/retail-store/tier5-src/_shared/restaurant-ordering.ts +201 -0
  57. package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +6 -0
  58. package/templates/yoga-studio/config.ts +12 -1
  59. package/templates/yoga-studio/tier5-src/_shared/himi-restaurants.ts +12 -5
@@ -385,3 +385,147 @@ export declare function deleteSavedPaymentMethod(savedPaymentMethodId: string):
385
385
  /** Make a saved payment method the member's primary one. The service declares this
386
386
  * as a GET (`@wix/auto_sdk_payments_saved-payment-methods` `markSavedPaymentMethodPrimary`). */
387
387
  export declare function markSavedPaymentMethodPrimary(savedPaymentMethodId: string): Promise<Record<string, never>>;
388
+ /** A Cart V2 money value — a decimal string, never a formatted one. */
389
+ export interface WixCartV2Money {
390
+ amount?: string;
391
+ convertedAmount?: string;
392
+ }
393
+ /** The address shape Cart V2 takes and returns. `subdivision` is ISO 3166-2 (`US-CA`). */
394
+ export interface WixCartV2Address {
395
+ country?: string;
396
+ subdivision?: string;
397
+ city?: string;
398
+ postalCode?: string;
399
+ addressLine?: string;
400
+ addressLine2?: string;
401
+ formattedAddress?: string;
402
+ }
403
+ /** One Cart V2 line. The catalog reference is under `source` (not top-level, as in V1),
404
+ * the image under `attributes`, and the name under `name` (not `productName`). */
405
+ export interface WixCartV2LineItem {
406
+ id?: string;
407
+ name?: {
408
+ original?: string;
409
+ translated?: string;
410
+ };
411
+ quantityInfo?: {
412
+ requestedQuantity?: number;
413
+ confirmedQuantity?: number;
414
+ availableQuantity?: number;
415
+ };
416
+ pricing?: {
417
+ unitPrice?: WixCartV2Money;
418
+ totalPrice?: WixCartV2Money;
419
+ };
420
+ source?: {
421
+ catalogReference?: WixCatalogReference;
422
+ rootCatalogItemId?: string;
423
+ };
424
+ attributes?: {
425
+ image?: {
426
+ url?: string;
427
+ };
428
+ };
429
+ /** `IN_STOCK` | `PARTIALLY_IN_STOCK` | `OUT_OF_STOCK` | `REMOVED_FROM_CATALOG`. */
430
+ status?: string;
431
+ }
432
+ export interface WixCartV2DeliveryMethod {
433
+ /** `PICKUP|ASAP`, `DELIVERY|ASAP`, or `<TYPE>|<startEpochMs>|<endEpochMs>` for Restaurants. */
434
+ code?: string;
435
+ appId?: string;
436
+ title?: {
437
+ original?: string;
438
+ translated?: string;
439
+ };
440
+ pickup?: boolean;
441
+ }
442
+ export interface WixCartV2 {
443
+ id?: string;
444
+ revision?: string;
445
+ lineItems?: WixCartV2LineItem[];
446
+ subtotal?: WixCartV2Money;
447
+ deliveryInfo?: {
448
+ address?: WixCartV2Address;
449
+ method?: WixCartV2DeliveryMethod;
450
+ };
451
+ businessInfo?: {
452
+ currencyCode?: string;
453
+ languageCode?: string;
454
+ };
455
+ customerInfo?: {
456
+ currencyCode?: string;
457
+ };
458
+ orderPlaced?: boolean;
459
+ }
460
+ export interface WixCartV2Violation {
461
+ /** `ERROR` | `WARNING`. */
462
+ severity?: string;
463
+ scope?: string;
464
+ code?: string;
465
+ description?: string;
466
+ }
467
+ export interface WixCartV2Summary {
468
+ priceSummary?: {
469
+ subtotal?: WixCartV2Money;
470
+ discount?: WixCartV2Money;
471
+ delivery?: WixCartV2Money;
472
+ additionalFees?: WixCartV2Money;
473
+ tax?: WixCartV2Money;
474
+ total?: WixCartV2Money;
475
+ };
476
+ violations?: WixCartV2Violation[];
477
+ }
478
+ export interface WixCartV2Response {
479
+ cart?: WixCartV2;
480
+ }
481
+ export interface WixEstimateCartV2Response {
482
+ cart?: WixCartV2;
483
+ summary?: WixCartV2Summary;
484
+ }
485
+ /** One catalog item to add: what it is (`catalogReference`) and how many. */
486
+ export interface WixCatalogItemInput {
487
+ catalogReference: WixCatalogReference;
488
+ quantity: number;
489
+ }
490
+ /** A quantity change for one existing line. */
491
+ export interface WixCartV2QuantityUpdate {
492
+ lineItemId: string;
493
+ quantity: number;
494
+ }
495
+ /** The Wix application error code a rejection carries (`DELIVERY_METHOD_NOT_FOUND`, …), or "".
496
+ * Read the same way as the empty-cart check: structurally, from the native `[CODE]` prefix,
497
+ * or from a cut web-bridge body in its canonical shape — never from prose. */
498
+ export declare function ecomApplicationErrorCode(error: unknown): string;
499
+ /** Read the current cart — GET /ecom/v2/carts/current. No cart yet is a successful read of an
500
+ * empty one: Wix answers 200 `{}` (or 404 `CURRENT_CART_NOT_FOUND`), resolved as `{ lineItems: [] }`.
501
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
502
+ export declare function getCurrentCartV2(): Promise<WixCartV2>;
503
+ /** Add catalog items to the current cart, creating it when there is none — POST
504
+ * /ecom/v2/carts/current/add-line-items `{ catalogItems }`. Adding an item already in the cart
505
+ * raises that line's quantity. Wix can drop an item it refuses and still answer 200, so read
506
+ * the returned cart for the line (and its `status`) rather than trusting the status code.
507
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
508
+ export declare function addLineItemsToCurrentCartV2(catalogItems: WixCatalogItemInput[]): Promise<WixCartV2Response>;
509
+ /** Set line quantities — POST /ecom/v2/carts/current/update-line-items
510
+ * `{ lineItems: [{ lineItemId, quantity: { newQuantity } }] }`.
511
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
512
+ export declare function updateLineItemsInCurrentCartV2(updates: WixCartV2QuantityUpdate[]): Promise<WixCartV2Response>;
513
+ /** Remove lines — POST /ecom/v2/carts/current/remove-line-items `{ lineItemIds }`.
514
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
515
+ export declare function removeLineItemsFromCurrentCartV2(lineItemIds: string[]): Promise<WixCartV2Response>;
516
+ /** Set the cart's delivery address — PATCH /ecom/v2/carts/current
517
+ * `{ cart: { deliveryInfo: { address } } }`. Restaurants needs one even for pickup (the
518
+ * restaurant's country is enough there); without it setting a method answers 428
519
+ * `DELIVERY_METHOD_MISSING_ADDRESS`.
520
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
521
+ export declare function updateCurrentCartV2DeliveryAddress(address: WixCartV2Address): Promise<WixCartV2Response>;
522
+ /** Choose how the cart is fulfilled — POST /ecom/v2/carts/current/set-delivery-method
523
+ * `{ deliveryMethod: { code } }`. 400 `DELIVERY_METHOD_NOT_FOUND` means no method of that code
524
+ * serves the cart's address (for Restaurants delivery: the address is outside every area).
525
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
526
+ export declare function setDeliveryMethodForCurrentCartV2(code: string, appId?: string): Promise<WixCartV2Response>;
527
+ /** Totals and blocking violations for the current cart — POST /ecom/v2/carts/current/estimate,
528
+ * always with `calculateDelivery` and `calculateTax` (a plain estimate reports a valid method as
529
+ * no longer available). No cart yet → `{ cart: { lineItems: [] } }`, not a throw.
530
+ * @scope visitor — the cart belongs to the session (visitor or member) that calls it. */
531
+ export declare function estimateCurrentCartV2(): Promise<WixEstimateCartV2Response>;
@@ -20,3 +20,96 @@ export interface WixQuerySectionsResponse {
20
20
  /** POST /restaurants/menus/v1/sections/query — menu sections (perm
21
21
  * RESTAURANTS.SECTION_READ; visitor-readable on sites with the Menus app). */
22
22
  export declare function querySections(req?: WixSectionQueryRequest): Promise<WixQuerySectionsResponse>;
23
+ /** An address as the Restaurants services return it. `subdivision` is ISO 3166-2 (`US-CA`). */
24
+ export interface WixRestaurantsAddress {
25
+ country?: string;
26
+ subdivision?: string;
27
+ city?: string;
28
+ postalCode?: string;
29
+ addressLine?: string;
30
+ formattedAddress?: string;
31
+ }
32
+ /** A Restaurants ordering operation (a "ordering page": hours, fulfillment methods, status). */
33
+ export interface WixOperation {
34
+ id: string;
35
+ name?: string;
36
+ /** The site's default operation. */
37
+ default?: boolean;
38
+ /** `ENABLED` takes orders; `DISABLED` and `PAUSED_UNTIL` (see `pausedUntilOptions.time`) do not. */
39
+ onlineOrderingStatus?: string;
40
+ pausedUntilOptions?: {
41
+ time?: string;
42
+ };
43
+ /** `PICKUP` | `DELIVERY`. */
44
+ defaultFulfillmentType?: string;
45
+ /** The fulfillment methods this operation offers — filter `listFulfillmentMethods` by these. */
46
+ fulfillmentIds?: string[];
47
+ businessLocationId?: string;
48
+ }
49
+ export interface WixListOperationsResponse {
50
+ operations: WixOperation[];
51
+ }
52
+ /** GET /restaurants-operations/v1/operations — every ordering operation on the site.
53
+ * @scope visitor — an anonymous visitor session is enough. */
54
+ export declare function listOperations(): Promise<WixListOperationsResponse>;
55
+ /** A pickup or delivery method. `fee` and `minOrderPrice` are decimal strings; a missing
56
+ * `fee` is 0. Only `enabled` methods may be offered. */
57
+ export interface WixFulfillmentMethod {
58
+ id: string;
59
+ name?: string;
60
+ /** `PICKUP` | `DELIVERY`. */
61
+ type?: string;
62
+ enabled?: boolean;
63
+ fee?: string;
64
+ minOrderPrice?: string;
65
+ pickupOptions?: {
66
+ address?: WixRestaurantsAddress;
67
+ instructions?: string;
68
+ };
69
+ deliveryOptions?: {
70
+ deliveryTimeInMinutes?: number;
71
+ freeDeliveryThreshold?: string;
72
+ };
73
+ businessLocationId?: string;
74
+ }
75
+ export interface WixListFulfillmentMethodsResponse {
76
+ fulfillmentMethods: WixFulfillmentMethod[];
77
+ pagingMetadata?: {
78
+ count?: number;
79
+ hasNext?: boolean;
80
+ cursors?: {
81
+ next?: string;
82
+ };
83
+ };
84
+ }
85
+ /** GET /fulfillment-methods/v1/fulfillment-methods — every pickup/delivery method on the site.
86
+ * There is no operation filter: keep the ids in the operation's `fulfillmentIds`.
87
+ * @scope visitor — an anonymous visitor session is enough. */
88
+ export declare function listFulfillmentMethods(opts?: {
89
+ limit?: number;
90
+ cursor?: string;
91
+ }): Promise<WixListFulfillmentMethodsResponse>;
92
+ /** The earliest orderable slot for one fulfillment type. An `ASAP` slot is ordered with the
93
+ * code `<TYPE>|ASAP`; a `PREORDER` slot with `<TYPE>|<startEpochMs>|<endEpochMs>`. */
94
+ export interface WixFulfillmentTimeSlot {
95
+ /** Wix spells this field with one "l": `PICKUP` | `DELIVERY`. */
96
+ fulfilmentType?: string;
97
+ timeSlot?: {
98
+ startTime?: string;
99
+ endTime?: string;
100
+ orderSchedulingType?: string;
101
+ };
102
+ fulfillmentInfo?: Array<{
103
+ fee?: string;
104
+ minOrderPrice?: string;
105
+ maxTime?: number;
106
+ }>;
107
+ }
108
+ export interface WixFirstAvailableTimeSlotsResponse {
109
+ timeslotsPerFulfillmentType: WixFulfillmentTimeSlot[];
110
+ }
111
+ /** GET /restaurants-operations/v1/operations/{operationId}/first-available-time-slot-per-fulfillment-type
112
+ * — the earliest orderable slot per type. Only orderable slots come back, so a type that is
113
+ * missing cannot be ordered now. Delivery is judged against `deliveryAddress` when given.
114
+ * @scope visitor — an anonymous visitor session is enough. */
115
+ export declare function getFirstAvailableTimeSlotPerFulfillmentType(operationId: string, deliveryAddress?: WixRestaurantsAddress): Promise<WixFirstAvailableTimeSlotsResponse>;
@@ -1368,13 +1368,16 @@ function classifyForApple(item, currency) {
1368
1368
  if (item.kind === "bookingsService") return bookingRoute(item, currency);
1369
1369
  return ticketRoute(item, currency);
1370
1370
  }
1371
+ var ADDRESSLESS_CUSTOM = "CUSTOM_WITHOUT_ADDRESS";
1372
+ var PHYSICAL_LOCATIONS = ["BUSINESS", "CUSTOMER", "CUSTOM", ADDRESSLESS_CUSTOM];
1371
1373
  function bookingRoute(item, currency) {
1372
1374
  if (item.onlineBooking !== true) return "decide";
1373
- if (item.conferencing === false && item.locations?.length && item.locations.every((type) => type === "BUSINESS" || type === "CUSTOMER" || type === "CUSTOM")) {
1375
+ if (item.conferencing === false && item.locations?.length && item.locations.every((type) => PHYSICAL_LOCATIONS.includes(type))) {
1374
1376
  return item.attendance === "online" ? "decide" : "wixPayments";
1375
1377
  }
1376
1378
  if (item.conferencing !== true || item.attendance === "physical") return "decide";
1377
- if (item.attendance !== "online" && (!item.locations || item.locations.length > 0)) return "decide";
1379
+ const addressed = item.locations?.filter((type) => type !== ADDRESSLESS_CUSTOM);
1380
+ if (item.attendance !== "online" && (!addressed || addressed.length > 0)) return "decide";
1378
1381
  if (item.type === "APPOINTMENT") {
1379
1382
  return item.capacity === 1 && item.maxParticipantsPerBooking === 1 ? "wixPayments" : "decide";
1380
1383
  }
@@ -1409,7 +1412,7 @@ function bookingAttendanceOf(raw) {
1409
1412
  maxParticipantsPerBooking: policy.enabled === true ? numeric(policy.maxParticipantsPerBooking) : void 0,
1410
1413
  hidden: boolean(s.hidden),
1411
1414
  conferencing: boolean(object(s.conferencing).enabled),
1412
- locations: Array.isArray(s.locations) ? s.locations.map((l) => text(object(l).type) ?? "UNKNOWN") : void 0,
1415
+ locations: Array.isArray(s.locations) ? s.locations.map(locationType) : void 0,
1413
1416
  onlineBooking: boolean(object(s.onlineBooking).enabled),
1414
1417
  onlinePayment: boolean(options.online),
1415
1418
  deposit: options.deposit === true || fixed.deposit !== void 0,
@@ -1418,6 +1421,19 @@ function bookingAttendanceOf(raw) {
1418
1421
  currency: text(price.currency)
1419
1422
  };
1420
1423
  }
1424
+ function locationType(raw) {
1425
+ const location = object(raw);
1426
+ const type = text(location.type) ?? "UNKNOWN";
1427
+ const addresses = [object(location.custom).address, location.calculatedAddress].map(object);
1428
+ return type === "CUSTOM" && addresses.every(describesNoPlace) ? ADDRESSLESS_CUSTOM : type;
1429
+ }
1430
+ function describesNoPlace(address) {
1431
+ const parts = ["country", "subdivision", "city", "postalCode", "addressLine", "addressLine2", "streetAddress", "location"];
1432
+ if (parts.some((key) => address[key] !== void 0 && address[key] !== "")) return false;
1433
+ const description = text(address.formattedAddress)?.trim() ?? "";
1434
+ return description === "" || ONLINE_LABEL.test(description);
1435
+ }
1436
+ var ONLINE_LABEL = /^(online|virtual)(\s+(class|classes|classroom|course|session|sessions|meeting|lesson|training|workshop|event))?$/i;
1421
1437
  function ticketAttendanceOf(event, definition) {
1422
1438
  const e = object(event);
1423
1439
  const t = object(definition);
@@ -3402,8 +3418,7 @@ async function reserveTicket(item, bridge, now) {
3402
3418
  if (isRefusal(held)) return creationRefused(held);
3403
3419
  const reservation = held.body;
3404
3420
  if (!isObject7(reservation) || !isNonEmpty3(reservation.id) || !future(reservation.expires, now)) return ORDER_CLOSED;
3405
- const invoice = isObject7(reservation.invoice) ? reservation.invoice : {};
3406
- if (!samePrice(invoice.grandTotal ?? invoice.total, item)) return CHANGED;
3421
+ if (!heldAsSelected(reservation, item)) return CHANGED;
3407
3422
  const placed = await bridge.call("POST", "/events/v1/checkout", { eventId: selected.eventId, reservationId: reservation.id, buyer: selected.buyer, ...selected.guests ? { guests: selected.guests } : {}, ...selected.buyerSubmission ? { buyerSubmission: selected.buyerSubmission } : {}, ...selected.guestSubmissions ? { guestSubmissions: selected.guestSubmissions } : {}, options: { silent: false, payInPerson: false, ignoreFormValidation: false, markAsPaid: false } });
3408
3423
  if (isRefusal(placed)) return attemptRefused(placed);
3409
3424
  const order = bodyObject(placed, "order");
@@ -3428,6 +3443,13 @@ async function reopen(order, bridge, accessOf3, now) {
3428
3443
  if (access === "none" || now && !future(order.verticalRef.expires, now)) return ORDER_CLOSED;
3429
3444
  return { status: "open", ...order };
3430
3445
  }
3446
+ function heldAsSelected(reservation, item) {
3447
+ if (isObject7(reservation.invoice)) return samePrice(reservation.invoice.grandTotal ?? reservation.invoice.total, item);
3448
+ const lines = reservation.reservations;
3449
+ if (!Array.isArray(lines) || lines.length !== 1 || !isObject7(lines[0]) || lines[0].quantity !== 1) return false;
3450
+ const held = lines[0].ticket;
3451
+ return isObject7(held) && held.id === item.reference.id && samePrice(held.price, item);
3452
+ }
3431
3453
  function samePrice(value, item) {
3432
3454
  return isObject7(value) && value.currency === item.attendance?.currency && decimal(value.amount) !== null && decimal(value.amount) === decimal(item.attendance?.amount);
3433
3455
  }
@@ -1384,13 +1384,16 @@ function attendanceCheckoutRoute(item, currency, platform) {
1384
1384
  const enabled = item.kind === "bookingsService" ? BOOKINGS_APPLE_SALES_ENABLED : EVENTS_APPLE_SALES_ENABLED;
1385
1385
  return platform === "ios" && route === "appleIap" && enabled ? "appleIap" : "blocked";
1386
1386
  }
1387
+ var ADDRESSLESS_CUSTOM = "CUSTOM_WITHOUT_ADDRESS";
1388
+ var PHYSICAL_LOCATIONS = ["BUSINESS", "CUSTOMER", "CUSTOM", ADDRESSLESS_CUSTOM];
1387
1389
  function bookingRoute(item, currency) {
1388
1390
  if (item.onlineBooking !== true) return "decide";
1389
- if (item.conferencing === false && item.locations?.length && item.locations.every((type) => type === "BUSINESS" || type === "CUSTOMER" || type === "CUSTOM")) {
1391
+ if (item.conferencing === false && item.locations?.length && item.locations.every((type) => PHYSICAL_LOCATIONS.includes(type))) {
1390
1392
  return item.attendance === "online" ? "decide" : "wixPayments";
1391
1393
  }
1392
1394
  if (item.conferencing !== true || item.attendance === "physical") return "decide";
1393
- if (item.attendance !== "online" && (!item.locations || item.locations.length > 0)) return "decide";
1395
+ const addressed = item.locations?.filter((type) => type !== ADDRESSLESS_CUSTOM);
1396
+ if (item.attendance !== "online" && (!addressed || addressed.length > 0)) return "decide";
1394
1397
  if (item.type === "APPOINTMENT") {
1395
1398
  return item.capacity === 1 && item.maxParticipantsPerBooking === 1 ? "wixPayments" : "decide";
1396
1399
  }
@@ -1425,7 +1428,7 @@ function bookingAttendanceOf(raw) {
1425
1428
  maxParticipantsPerBooking: policy.enabled === true ? numeric(policy.maxParticipantsPerBooking) : void 0,
1426
1429
  hidden: boolean(s.hidden),
1427
1430
  conferencing: boolean(object(s.conferencing).enabled),
1428
- locations: Array.isArray(s.locations) ? s.locations.map((l) => text(object(l).type) ?? "UNKNOWN") : void 0,
1431
+ locations: Array.isArray(s.locations) ? s.locations.map(locationType) : void 0,
1429
1432
  onlineBooking: boolean(object(s.onlineBooking).enabled),
1430
1433
  onlinePayment: boolean(options.online),
1431
1434
  deposit: options.deposit === true || fixed.deposit !== void 0,
@@ -1434,6 +1437,19 @@ function bookingAttendanceOf(raw) {
1434
1437
  currency: text(price.currency)
1435
1438
  };
1436
1439
  }
1440
+ function locationType(raw) {
1441
+ const location = object(raw);
1442
+ const type = text(location.type) ?? "UNKNOWN";
1443
+ const addresses = [object(location.custom).address, location.calculatedAddress].map(object);
1444
+ return type === "CUSTOM" && addresses.every(describesNoPlace) ? ADDRESSLESS_CUSTOM : type;
1445
+ }
1446
+ function describesNoPlace(address) {
1447
+ const parts = ["country", "subdivision", "city", "postalCode", "addressLine", "addressLine2", "streetAddress", "location"];
1448
+ if (parts.some((key) => address[key] !== void 0 && address[key] !== "")) return false;
1449
+ const description = text(address.formattedAddress)?.trim() ?? "";
1450
+ return description === "" || ONLINE_LABEL.test(description);
1451
+ }
1452
+ var ONLINE_LABEL = /^(online|virtual)(\s+(class|classes|classroom|course|session|sessions|meeting|lesson|training|workshop|event))?$/i;
1437
1453
  function ticketAttendanceOf(event, definition) {
1438
1454
  const e = object(event);
1439
1455
  const t = object(definition);
@@ -1934,13 +1934,16 @@ function classifyForApple(item, currency) {
1934
1934
  if (item.kind === "bookingsService") return bookingRoute(item, currency);
1935
1935
  return ticketRoute(item, currency);
1936
1936
  }
1937
+ var ADDRESSLESS_CUSTOM = "CUSTOM_WITHOUT_ADDRESS";
1938
+ var PHYSICAL_LOCATIONS = ["BUSINESS", "CUSTOMER", "CUSTOM", ADDRESSLESS_CUSTOM];
1937
1939
  function bookingRoute(item, currency) {
1938
1940
  if (item.onlineBooking !== true) return "decide";
1939
- if (item.conferencing === false && item.locations?.length && item.locations.every((type) => type === "BUSINESS" || type === "CUSTOMER" || type === "CUSTOM")) {
1941
+ if (item.conferencing === false && item.locations?.length && item.locations.every((type) => PHYSICAL_LOCATIONS.includes(type))) {
1940
1942
  return item.attendance === "online" ? "decide" : "wixPayments";
1941
1943
  }
1942
1944
  if (item.conferencing !== true || item.attendance === "physical") return "decide";
1943
- if (item.attendance !== "online" && (!item.locations || item.locations.length > 0)) return "decide";
1945
+ const addressed = item.locations?.filter((type) => type !== ADDRESSLESS_CUSTOM);
1946
+ if (item.attendance !== "online" && (!addressed || addressed.length > 0)) return "decide";
1944
1947
  if (item.type === "APPOINTMENT") {
1945
1948
  return item.capacity === 1 && item.maxParticipantsPerBooking === 1 ? "wixPayments" : "decide";
1946
1949
  }
@@ -1975,7 +1978,7 @@ function bookingAttendanceOf(raw) {
1975
1978
  maxParticipantsPerBooking: policy.enabled === true ? numeric(policy.maxParticipantsPerBooking) : void 0,
1976
1979
  hidden: boolean(s2.hidden),
1977
1980
  conferencing: boolean(object(s2.conferencing).enabled),
1978
- locations: Array.isArray(s2.locations) ? s2.locations.map((l) => text(object(l).type) ?? "UNKNOWN") : void 0,
1981
+ locations: Array.isArray(s2.locations) ? s2.locations.map(locationType) : void 0,
1979
1982
  onlineBooking: boolean(object(s2.onlineBooking).enabled),
1980
1983
  onlinePayment: boolean(options.online),
1981
1984
  deposit: options.deposit === true || fixed.deposit !== void 0,
@@ -1984,6 +1987,19 @@ function bookingAttendanceOf(raw) {
1984
1987
  currency: text(price.currency)
1985
1988
  };
1986
1989
  }
1990
+ function locationType(raw) {
1991
+ const location = object(raw);
1992
+ const type = text(location.type) ?? "UNKNOWN";
1993
+ const addresses = [object(location.custom).address, location.calculatedAddress].map(object);
1994
+ return type === "CUSTOM" && addresses.every(describesNoPlace) ? ADDRESSLESS_CUSTOM : type;
1995
+ }
1996
+ function describesNoPlace(address) {
1997
+ const parts = ["country", "subdivision", "city", "postalCode", "addressLine", "addressLine2", "streetAddress", "location"];
1998
+ if (parts.some((key) => address[key] !== void 0 && address[key] !== "")) return false;
1999
+ const description = text(address.formattedAddress)?.trim() ?? "";
2000
+ return description === "" || ONLINE_LABEL.test(description);
2001
+ }
2002
+ var ONLINE_LABEL = /^(online|virtual)(\s+(class|classes|classroom|course|session|sessions|meeting|lesson|training|workshop|event))?$/i;
1987
2003
  function ticketAttendanceOf(event, definition) {
1988
2004
  const e = object(event);
1989
2005
  const t = object(definition);
@@ -3782,8 +3798,7 @@ async function reserveTicket(item, bridge, now) {
3782
3798
  if (isRefusal(held)) return creationRefused(held);
3783
3799
  const reservation = held.body;
3784
3800
  if (!isObject7(reservation) || !isNonEmpty3(reservation.id) || !future(reservation.expires, now)) return ORDER_CLOSED;
3785
- const invoice = isObject7(reservation.invoice) ? reservation.invoice : {};
3786
- if (!samePrice(invoice.grandTotal ?? invoice.total, item)) return CHANGED;
3801
+ if (!heldAsSelected(reservation, item)) return CHANGED;
3787
3802
  const placed = await bridge.call("POST", "/events/v1/checkout", { eventId: selected.eventId, reservationId: reservation.id, buyer: selected.buyer, ...selected.guests ? { guests: selected.guests } : {}, ...selected.buyerSubmission ? { buyerSubmission: selected.buyerSubmission } : {}, ...selected.guestSubmissions ? { guestSubmissions: selected.guestSubmissions } : {}, options: { silent: false, payInPerson: false, ignoreFormValidation: false, markAsPaid: false } });
3788
3803
  if (isRefusal(placed)) return attemptRefused(placed);
3789
3804
  const order = bodyObject(placed, "order");
@@ -3808,6 +3823,13 @@ async function reopen(order, bridge, accessOf2, now) {
3808
3823
  if (access === "none" || now && !future(order.verticalRef.expires, now)) return ORDER_CLOSED;
3809
3824
  return { status: "open", ...order };
3810
3825
  }
3826
+ function heldAsSelected(reservation, item) {
3827
+ if (isObject7(reservation.invoice)) return samePrice(reservation.invoice.grandTotal ?? reservation.invoice.total, item);
3828
+ const lines = reservation.reservations;
3829
+ if (!Array.isArray(lines) || lines.length !== 1 || !isObject7(lines[0]) || lines[0].quantity !== 1) return false;
3830
+ const held = lines[0].ticket;
3831
+ return isObject7(held) && held.id === item.reference.id && samePrice(held.price, item);
3832
+ }
3811
3833
  function samePrice(value, item) {
3812
3834
  return isObject7(value) && value.currency === item.attendance?.currency && decimal(value.amount) !== null && decimal(value.amount) === decimal(item.attendance?.amount);
3813
3835
  }
@@ -184,6 +184,56 @@ function deleteSavedPaymentMethod(savedPaymentMethodId) {
184
184
  function markSavedPaymentMethodPrimary(savedPaymentMethodId) {
185
185
  return wixCall("GET", `${savedPaymentMethodPath(savedPaymentMethodId, "markSavedPaymentMethodPrimary")}/mark-primary`);
186
186
  }
187
+ var CURRENT_CART_V2 = "/ecom/v2/carts/current";
188
+ var CURRENT_CART_NOT_FOUND = "CURRENT_CART_NOT_FOUND";
189
+ function ecomApplicationErrorCode(error) {
190
+ return applicationErrorCode(error);
191
+ }
192
+ function isEmptyCurrentCartV2Error(error) {
193
+ const code = applicationErrorCode(error);
194
+ return code === CURRENT_CART_NOT_FOUND || code === OWNED_CART_NOT_FOUND;
195
+ }
196
+ async function getCurrentCartV2() {
197
+ try {
198
+ const r = await wixCall("GET", CURRENT_CART_V2);
199
+ return r?.cart ?? { lineItems: [] };
200
+ } catch (e) {
201
+ if (isEmptyCurrentCartV2Error(e)) return { lineItems: [] };
202
+ throw e;
203
+ }
204
+ }
205
+ function addLineItemsToCurrentCartV2(catalogItems) {
206
+ if (!catalogItems?.length) throw new Error("addLineItemsToCurrentCartV2: at least one catalog item is required");
207
+ return wixCall("POST", `${CURRENT_CART_V2}/add-line-items`, { catalogItems });
208
+ }
209
+ function updateLineItemsInCurrentCartV2(updates) {
210
+ if (!updates?.length) throw new Error("updateLineItemsInCurrentCartV2: at least one update is required");
211
+ return wixCall("POST", `${CURRENT_CART_V2}/update-line-items`, {
212
+ lineItems: updates.map((u) => ({ lineItemId: u.lineItemId, quantity: { newQuantity: Math.max(1, Math.floor(u.quantity)) } }))
213
+ });
214
+ }
215
+ function removeLineItemsFromCurrentCartV2(lineItemIds) {
216
+ if (!lineItemIds?.length) throw new Error("removeLineItemsFromCurrentCartV2: at least one line item id is required");
217
+ return wixCall("POST", `${CURRENT_CART_V2}/remove-line-items`, { lineItemIds });
218
+ }
219
+ function updateCurrentCartV2DeliveryAddress(address) {
220
+ if (!address?.country) throw new Error("updateCurrentCartV2DeliveryAddress: address.country is required");
221
+ return wixCall("PATCH", CURRENT_CART_V2, { cart: { deliveryInfo: { address } } });
222
+ }
223
+ function setDeliveryMethodForCurrentCartV2(code, appId) {
224
+ if (!code) throw new Error("setDeliveryMethodForCurrentCartV2: code is required");
225
+ return wixCall("POST", `${CURRENT_CART_V2}/set-delivery-method`, {
226
+ deliveryMethod: { code, ...appId ? { appId } : {} }
227
+ });
228
+ }
229
+ async function estimateCurrentCartV2() {
230
+ try {
231
+ return await wixCall("POST", `${CURRENT_CART_V2}/estimate`, { calculateDelivery: true, calculateTax: true });
232
+ } catch (e) {
233
+ if (isEmptyCurrentCartV2Error(e)) return { cart: { lineItems: [] } };
234
+ throw e;
235
+ }
236
+ }
187
237
 
188
238
  // ../../stdlib/wix-sdk/ecom/src/index.ts
189
239
  function wixCallHeaders(opts) {
@@ -213,6 +263,7 @@ function searchOrders(req = {}, opts) {
213
263
  }
214
264
  export {
215
265
  addCouponToCurrentCart,
266
+ addLineItemsToCurrentCartV2,
216
267
  addToCurrentCart,
217
268
  archiveOrder,
218
269
  calculateCurrentCart,
@@ -224,7 +275,10 @@ export {
224
275
  createOrderFulfillment,
225
276
  deleteMemberAddress,
226
277
  deleteSavedPaymentMethod,
278
+ ecomApplicationErrorCode,
279
+ estimateCurrentCartV2,
227
280
  getCurrentCart,
281
+ getCurrentCartV2,
228
282
  getDefaultMemberAddress,
229
283
  getMemberAddress,
230
284
  getOrder,
@@ -239,8 +293,12 @@ export {
239
293
  refundPayments,
240
294
  removeCouponFromCurrentCart,
241
295
  removeLineItemsFromCurrentCart,
296
+ removeLineItemsFromCurrentCartV2,
242
297
  searchOrders,
243
298
  setDefaultMemberAddress,
299
+ setDeliveryMethodForCurrentCartV2,
300
+ updateCurrentCartV2DeliveryAddress,
301
+ updateLineItemsInCurrentCartV2,
244
302
  updateLineItemsQuantity,
245
303
  updateMemberAddress,
246
304
  wixCall
@@ -6,6 +6,26 @@ function querySections(req = {}) {
6
6
  req
7
7
  );
8
8
  }
9
+ function listOperations() {
10
+ return wixCall("GET", "/restaurants-operations/v1/operations");
11
+ }
12
+ function listFulfillmentMethods(opts = {}) {
13
+ const query = [];
14
+ if (opts.limit) query.push(`cursorPaging.limit=${Math.max(1, Math.min(100, Math.floor(opts.limit)))}`);
15
+ if (opts.cursor) query.push(`cursorPaging.cursor=${encodeURIComponent(opts.cursor)}`);
16
+ return wixCall(
17
+ "GET",
18
+ `/fulfillment-methods/v1/fulfillment-methods${query.length ? `?${query.join("&")}` : ""}`
19
+ );
20
+ }
21
+ function getFirstAvailableTimeSlotPerFulfillmentType(operationId, deliveryAddress) {
22
+ if (!operationId) throw new Error("getFirstAvailableTimeSlotPerFulfillmentType: operationId is required");
23
+ const query = Object.entries(deliveryAddress ?? {}).filter(([, value]) => typeof value === "string" && value.trim()).map(([key, value]) => `deliveryAddress.${key}=${encodeURIComponent(String(value).trim())}`);
24
+ return wixCall(
25
+ "GET",
26
+ `/restaurants-operations/v1/operations/${encodeURIComponent(operationId)}/first-available-time-slot-per-fulfillment-type${query.length ? `?${query.join("&")}` : ""}`
27
+ );
28
+ }
9
29
 
10
30
  // ../../stdlib/wix-sdk/restaurants/src/index.ts
11
31
  function wixCallHeaders(opts) {
@@ -79,9 +99,12 @@ function getOrder(id, opts) {
79
99
  );
80
100
  }
81
101
  export {
102
+ getFirstAvailableTimeSlotPerFulfillmentType,
82
103
  getItem,
83
104
  getMenu,
84
105
  getOrder,
106
+ listFulfillmentMethods,
107
+ listOperations,
85
108
  queryItems,
86
109
  queryMenus,
87
110
  queryOrders,