@wix/himalaya-cli 0.1551.0 → 0.1553.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 (65) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +3 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-contract.d.ts +2 -2
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +24 -2
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/order-refs.d.ts +12 -3
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/forms/src/extensions.d.ts +83 -1
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +146 -23
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +8 -5
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +147 -24
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-forms.mjs +19 -0
  10. package/dist/cli.mjs +2513 -2201
  11. package/dist/preview-assets.generated.bin +0 -0
  12. package/fixtures/wix-canned.json +14 -7
  13. package/guides/getting-started.md +17 -1
  14. package/guides/headless-loop.md +7 -1
  15. package/guides/himi-skill.md +17 -1
  16. package/guides/himi-test.md +95 -7
  17. package/guides/iap-pricing.md +1 -1
  18. package/guides/iap-products.md +2 -2
  19. package/guides/iap-screen-adoption.md +1 -1
  20. package/guides/index.json +1 -1
  21. package/guides/sdk-reference.json +82 -4
  22. package/guides/skill.md +16 -0
  23. package/package.json +2 -2
  24. package/templates/beauty-salon/config.ts +13 -0
  25. package/templates/beauty-salon/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  26. package/templates/beauty-salon/tier5-src/_shared/iap-worker.ts +1 -1
  27. package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +1 -1
  28. package/templates/branded-lite/config.ts +13 -0
  29. package/templates/branded-lite/dev/index.ts +1338 -2011
  30. package/templates/branded-lite/tier5-src/_shared/branded-form.ts +262 -0
  31. package/templates/branded-lite/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  32. package/templates/branded-lite/tier5-src/_shared/iap-worker.ts +1 -1
  33. package/templates/branded-lite/tier5-src/himi-branded-lite-form/index.ts +399 -0
  34. package/templates/branded-lite/tier5-src/himi-branded-lite-forms/index.ts +22 -7
  35. package/templates/branded-lite/tier5-src/himi-store-product/index.ts +1 -1
  36. package/templates/community-club/config.ts +13 -0
  37. package/templates/community-club/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  38. package/templates/community-club/tier5-src/_shared/iap-worker.ts +1 -1
  39. package/templates/events-meetups/config.ts +13 -0
  40. package/templates/events-meetups/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  41. package/templates/events-meetups/tier5-src/_shared/iap-worker.ts +1 -1
  42. package/templates/gym-fitness/config.ts +13 -0
  43. package/templates/gym-fitness/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  44. package/templates/gym-fitness/tier5-src/_shared/iap-worker.ts +1 -1
  45. package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +1 -1
  46. package/templates/nonprofit-cause/config.ts +13 -0
  47. package/templates/nonprofit-cause/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  48. package/templates/nonprofit-cause/tier5-src/_shared/iap-worker.ts +1 -1
  49. package/templates/podcast-creator/config.ts +13 -0
  50. package/templates/podcast-creator/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  51. package/templates/podcast-creator/tier5-src/_shared/iap-worker.ts +1 -1
  52. package/templates/portfolio-creative/config.ts +13 -0
  53. package/templates/portfolio-creative/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  54. package/templates/portfolio-creative/tier5-src/_shared/iap-worker.ts +1 -1
  55. package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +1 -1
  56. package/templates/restaurant/config.ts +13 -0
  57. package/templates/restaurant/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  58. package/templates/restaurant/tier5-src/_shared/iap-worker.ts +1 -1
  59. package/templates/retail-store/config.ts +13 -0
  60. package/templates/retail-store/tier5-src/_shared/iap-worker.ts +1 -1
  61. package/templates/retail-store/tier5-src/himi-store-product/index.ts +1 -1
  62. package/templates/yoga-studio/config.ts +13 -0
  63. package/templates/yoga-studio/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
  64. package/templates/yoga-studio/tier5-src/_shared/iap-worker.ts +1 -1
  65. package/templates/branded-lite/tier5-src/wix-spaces-form-detail/index.ts +0 -30
@@ -1240,8 +1240,8 @@ var sameReference = (value, reference) => isObject2(value) && value.kind === ref
1240
1240
 
1241
1241
  // ../../core/sdk/iap/src/wix-payments-contract.ts
1242
1242
  var HIMALAYA_SERVE_IAP_ROUTE = { prefix: "/himalaya-serve/v1/iap" };
1243
- var BOOKINGS_APPLE_SALES_ENABLED = false;
1244
- var EVENTS_APPLE_SALES_ENABLED = false;
1243
+ var BOOKINGS_APPLE_SALES_ENABLED = true;
1244
+ var EVENTS_APPLE_SALES_ENABLED = true;
1245
1245
  var ATTENDANCE_SALE_RULE = { appProductId: (id2) => id2, productType: "CONSUMABLE" };
1246
1246
  var STORES_ITEM_PAYMENT_ENABLED = false;
1247
1247
  var STORES_APPLE_SALES_ENABLED = true;
@@ -2005,10 +2005,13 @@ function locationType(raw) {
2005
2005
  return type === "CUSTOM" && addresses.every(describesNoPlace) ? ADDRESSLESS_CUSTOM : type;
2006
2006
  }
2007
2007
  function describesNoPlace(address) {
2008
- const parts = ["country", "subdivision", "city", "postalCode", "addressLine", "addressLine2", "streetAddress", "location"];
2008
+ const parts = ["country", "subdivision", "city", "postalCode", "addressLine2", "streetAddress", "location"];
2009
2009
  if (parts.some((key) => address[key] !== void 0 && address[key] !== "")) return false;
2010
- const description = text(address.formattedAddress)?.trim() ?? "";
2011
- return description === "" || ONLINE_LABEL.test(description);
2010
+ return [address.addressLine, address.formattedAddress].every((value) => {
2011
+ if (value !== void 0 && typeof value !== "string") return false;
2012
+ const description = value?.trim() ?? "";
2013
+ return description === "" || ONLINE_LABEL.test(description);
2014
+ });
2012
2015
  }
2013
2016
  var ONLINE_LABEL = /^(online|virtual)(\s+(class|classes|classroom|course|session|sessions|meeting|lesson|training|workshop|event))?$/i;
2014
2017
  function ticketAttendanceOf(event, definition) {
@@ -2272,9 +2275,33 @@ function isFinalRefusal(status) {
2272
2275
  var NEEDS_SUPPORT_HOLD_MS = 6048e5;
2273
2276
  var ITEM_START_HOLD_MS = 36e5;
2274
2277
  function pruneExpiredHolds(partition, now) {
2275
- const expired = partition.refs().filter((ref) => now - ref.updatedAt >= (HOLD_MS[ref.stage] ?? Infinity));
2278
+ const expired = partition.refs().filter((ref) => now - ref.updatedAt >= (HOLD_MS[ref.stage] ?? Infinity) || released(ref, now));
2276
2279
  return expired.filter((ref) => partition.remove(ref.key)).map((ref) => ref.key);
2277
2280
  }
2281
+ var OPENING_SETTLE_MS = 3e5;
2282
+ async function settleOpening(partition, adapter, guard, item, bridge, now) {
2283
+ const resolve = adapter.resolveOpening;
2284
+ if (!resolve) return "held";
2285
+ let current = guard;
2286
+ const claim = () => {
2287
+ const next = { ...current, updatedAt: now };
2288
+ if (!isStoredGuard(partition, current) || !partition.put(next)) return false;
2289
+ current = next;
2290
+ return true;
2291
+ };
2292
+ const resolution = await resolve(guard, item, bridge, { settled: now - guard.updatedAt >= OPENING_SETTLE_MS, claim });
2293
+ if (isStoredGuard(partition, current)) {
2294
+ if (resolution !== "released") return resolution;
2295
+ return partition.remove(guard.key) ? "released" : "storageUnavailable";
2296
+ }
2297
+ const stored = partition.refs().find((ref) => ref.key === guard.key);
2298
+ if (!stored) return "released";
2299
+ return stored.stage === "openingOrder" ? resolve(stored, item, bridge, { settled: false, claim: () => false }) : "held";
2300
+ }
2301
+ function isStoredGuard(partition, guard) {
2302
+ const stored = partition.refs().find((ref) => ref.key === guard.key);
2303
+ return stored?.stage === "openingOrder" && stored.updatedAt === guard.updatedAt;
2304
+ }
2278
2305
  var MAX_ORDER_REFS = 16;
2279
2306
  function createWorkerOrderRefStore(storage) {
2280
2307
  const kv = () => storage ?? hostStorage();
@@ -2351,10 +2378,14 @@ function writeVerified(store, location, value) {
2351
2378
  function isOrderRef(value) {
2352
2379
  if (!isObject6(value) || typeof value.key !== "string" || !STAGES.has(value.stage)) return false;
2353
2380
  if (typeof value.updatedAt !== "number") return false;
2381
+ if (value.releaseAt !== void 0 && typeof value.releaseAt !== "number") return false;
2354
2382
  const optional = ["kind", "cashierOrderId", "wixTransactionId", "paymentId", "storeProductId", "appProductId", "appleTransactionId", "appAccountToken"];
2355
2383
  if (!optional.every((field) => value[field] === void 0 || typeof value[field] === "string")) return false;
2356
2384
  return value.verticalRef === void 0 || isStringMap(value.verticalRef);
2357
2385
  }
2386
+ function released(ref, now) {
2387
+ return ref.stage === "openingOrder" && ref.releaseAt !== void 0 && now >= ref.releaseAt;
2388
+ }
2358
2389
  function isPartitionKey(key) {
2359
2390
  return isUUID3(key.purchasesAppId) && isUUID3(key.siteId) && isUUID3(key.memberId);
2360
2391
  }
@@ -2491,6 +2522,8 @@ function createWixOrderBackend(deps) {
2491
2522
  async function getPurchaseContext(session, catalogRef) {
2492
2523
  const sale = await saleFor(session, catalogRef);
2493
2524
  if (isStop(sale)) return contextResult(catalogRef, sale);
2525
+ const unresolved = await resolveOpenings(sale);
2526
+ if (unresolved) return contextResult(catalogRef, unresolved);
2494
2527
  const blocked = saleBlocked(sale);
2495
2528
  if (blocked) return contextResult(catalogRef, blocked);
2496
2529
  const itemPayment = deps.itemPaymentEnabled ? sale.adapter.itemPayment?.(sale.item) : null;
@@ -2509,11 +2542,26 @@ function createWixOrderBackend(deps) {
2509
2542
  if (failure3) return stopWith("rejected", failure3);
2510
2543
  if (sale.adapter.repeatable) {
2511
2544
  const prefix = `${sale.item.reference.kind}:${sale.item.reference.id}#`;
2512
- const unresolved = sale.partition.refs().find((ref) => ref.key.startsWith(prefix) && ["openingOrder", "held", "needsSupport"].includes(ref.stage));
2513
- if (unresolved) return stopWith("rejected", unresolved.stage === "openingOrder" ? "outcomeUnknown" : "needsSupport");
2545
+ const unresolved = sale.partition.refs().find((ref) => ref.key.startsWith(prefix) && !sale.unrelated.has(ref.key) && ["openingOrder", "held", "needsSupport"].includes(ref.stage));
2546
+ if (unresolved) return stopWith("rejected", unresolved.stage === "openingOrder" ? "paymentInProgress" : "needsSupport");
2514
2547
  }
2515
2548
  return deps.productBusy?.(sale.appleProduct.productId) ? stopWith("rejected", "paymentInProgress") : null;
2516
2549
  }
2550
+ async function resolveOpenings(sale) {
2551
+ if (!sale.adapter.repeatable || !sale.adapter.resolveOpening) return null;
2552
+ for (const guard of openingsOf(sale)) {
2553
+ const resolution = await settleOpening(sale.partition, sale.adapter, guard, sale.item, sale.bridge, now());
2554
+ if (!sale.bridge.isCurrent() || resolution === "sessionChanged") return STALE2;
2555
+ if (resolution === "unavailable") return retry("unavailable");
2556
+ if (resolution === "storageUnavailable") return stopWith("rejected", "storageUnavailable");
2557
+ if (resolution === "unrelated") sale.unrelated.add(guard.key);
2558
+ }
2559
+ return null;
2560
+ }
2561
+ function openingsOf(sale) {
2562
+ const prefix = `${sale.item.reference.kind}:${sale.item.reference.id}#`;
2563
+ return sale.partition.refs().filter((ref) => ref.stage === "openingOrder" && ref.key.startsWith(prefix));
2564
+ }
2517
2565
  async function saleFor(session, catalogRef) {
2518
2566
  const sold = deps.itemFor(catalogRef);
2519
2567
  const adapter = sold && adapterFor(sold.item.reference.kind);
@@ -2534,13 +2582,15 @@ function createWixOrderBackend(deps) {
2534
2582
  adapter,
2535
2583
  member,
2536
2584
  partition: member.partition,
2537
- bridge: bindBridge(session, deps.session, deps.bridge)
2585
+ bridge: bindBridge(session, deps.session, deps.bridge),
2586
+ unrelated: /* @__PURE__ */ new Set()
2538
2587
  };
2539
2588
  }
2540
2589
  async function orderFor(sale) {
2541
2590
  const existing = refAt(sale.partition, sale.catalogRef);
2542
2591
  let prevented;
2543
- const beforeCreate = () => {
2592
+ let guarded;
2593
+ const beforeCreate = (guard = {}) => {
2544
2594
  if (!sale.adapter.repeatable || existing) return true;
2545
2595
  if (!sale.bridge.isCurrent()) {
2546
2596
  prevented = STALE2;
@@ -2551,18 +2601,30 @@ function createWixOrderBackend(deps) {
2551
2601
  prevented = blocked;
2552
2602
  return false;
2553
2603
  }
2554
- const opening = persist(sale, { key: sale.catalogRef, kind: sale.adapter.kind, stage: "openingOrder", updatedAt: now() });
2604
+ const opening = persist(sale, { ...guard, key: sale.catalogRef, kind: sale.adapter.kind, stage: "openingOrder", updatedAt: now() });
2555
2605
  if (isStop(opening)) {
2556
2606
  prevented = opening;
2557
2607
  return false;
2558
2608
  }
2609
+ guarded = opening.updatedAt;
2559
2610
  return true;
2560
2611
  };
2561
- const attempt4 = existing?.cashierOrderId && existing.verticalRef ? await reopenOrOpen(sale, { cashierOrderId: existing.cashierOrderId, verticalRef: existing.verticalRef }) : await sale.adapter.openOrder(sale.item, sale.bridge, beforeCreate);
2612
+ const afterCreate = (guard) => {
2613
+ const opening = refAt(sale.partition, sale.catalogRef);
2614
+ if (opening?.stage !== "openingOrder" || opening.updatedAt !== guarded) return;
2615
+ const recorded = persist(sale, { ...opening, ...guard, verticalRef: { ...opening.verticalRef, ...guard.verticalRef }, updatedAt: now() });
2616
+ if (!isStop(recorded)) guarded = recorded.updatedAt;
2617
+ };
2618
+ const attempt4 = existing?.cashierOrderId && existing.verticalRef ? await reopenOrOpen(sale, { cashierOrderId: existing.cashierOrderId, verticalRef: existing.verticalRef }) : await sale.adapter.openOrder(sale.item, sale.bridge, beforeCreate, afterCreate);
2562
2619
  if (prevented) return prevented;
2620
+ if (guarded !== void 0 && attempt4.status === "open" && !stillGuarded(sale, guarded)) return retry("unavailable");
2563
2621
  const ref = recordOrder(sale, existing, attempt4);
2564
2622
  return isStop(ref) ? ref : { ref, placed: isPlaced(attempt4) };
2565
2623
  }
2624
+ function stillGuarded(sale, guarded) {
2625
+ const stored = refAt(sale.partition, sale.catalogRef);
2626
+ return stored?.stage === "openingOrder" && stored.updatedAt === guarded;
2627
+ }
2566
2628
  async function reopenOrOpen(sale, order) {
2567
2629
  const reopened = await sale.adapter.reopenOrder(order, sale.bridge);
2568
2630
  const closed = reopened.status === "refused" && reopened.reason === "orderClosed";
@@ -2805,8 +2867,9 @@ var NOT_CONFIGURED = { stop: true, result: "rejected", failure: "notConfigured"
2805
2867
  var UNAVAILABLE = { stop: true, result: "retryable", failure: "unavailable" };
2806
2868
  var OUTCOME_UNKNOWN = { stop: true, result: "rejected", failure: "outcomeUnknown" };
2807
2869
  var BLOCKING_STAGES = {
2870
+ // A repeatable sale's guard settles on a later tap, so it keeps the action tappable.
2808
2871
  startingItem: "outcomeUnknown",
2809
- openingOrder: "outcomeUnknown",
2872
+ openingOrder: "paymentInProgress",
2810
2873
  submitted: "paymentInProgress",
2811
2874
  held: "paymentHeld",
2812
2875
  needsSupport: "needsSupport"
@@ -3065,6 +3128,7 @@ function enabledCheckout(deps) {
3065
3128
  if (!tracked) return backOffDue();
3066
3129
  partitionRead = null;
3067
3130
  for (const key of pruneExpiredHolds(tracked.partition, deps.clock.now())) payments.delete(key);
3131
+ if (!options.dueOnly) await settleOpenings(session, tracked.partition);
3068
3132
  for (const ref of tracked.partition.refs()) {
3069
3133
  if (!isCurrent(session)) return;
3070
3134
  if (ref.stage === "needsSupport") setPayment(ref.key, "needsSupport");
@@ -3080,6 +3144,13 @@ function enabledCheckout(deps) {
3080
3144
  }
3081
3145
  publish();
3082
3146
  }
3147
+ async function settleOpenings(session, partition) {
3148
+ for (const ref of partition.refs()) {
3149
+ const adapter = deps.adapters.find((candidate) => candidate.kind === ref.kind);
3150
+ if (ref.stage !== "openingOrder" || !adapter?.resolveOpening || !isCurrent(session)) continue;
3151
+ await settleOpening(partition, adapter, ref, void 0, bindBridge(session, deps.session, bridge), deps.clock.now());
3152
+ }
3153
+ }
3083
3154
  async function trackedPartition(session) {
3084
3155
  const binding = await bindingOf(deps.binding);
3085
3156
  if (!binding || !isCurrent(session)) return binding === null ? "none" : null;
@@ -3713,6 +3784,12 @@ var BOOKING = "bookingsService";
3713
3784
  var TICKET = "eventsTicket";
3714
3785
  var NOT_ENABLED = { status: "refused", reason: "notEnabled" };
3715
3786
  var CHANGED = { status: "refused", reason: "productChanged" };
3787
+ var MINUTE_MS = 6e4;
3788
+ var RELEASE_MARGIN_MS = 3e5;
3789
+ var DEFAULT_RESERVATION_MINUTES = 60;
3790
+ var PAYMENT_TAKEN = ["PAID", "PARTIALLY_PAID", "EXEMPT", "REFUNDED"];
3791
+ var HAS_OFFSET = /(?:Z|[+-]\d{2}:?\d{2})$/i;
3792
+ var LATEST_ZONE_MS = 432e5;
3716
3793
  function attendanceOrdersWith(options) {
3717
3794
  const now = options.now ?? Date.now;
3718
3795
  return {
@@ -3720,7 +3797,8 @@ function attendanceOrdersWith(options) {
3720
3797
  kind: BOOKING,
3721
3798
  repeatable: true,
3722
3799
  eligibility: (item) => eligible(item, BOOKING, options.bookingsEnabled),
3723
- openOrder: (item, bridge, beforeCreate) => options.bookingsEnabled ? openBooking(item, bridge, beforeCreate) : Promise.resolve(NOT_ENABLED),
3800
+ openOrder: (item, bridge, beforeCreate, afterCreate) => options.bookingsEnabled ? openBooking(item, bridge, beforeCreate, afterCreate) : Promise.resolve(NOT_ENABLED),
3801
+ resolveOpening: resolveBookingOpening,
3724
3802
  readAccess: bookingAccess,
3725
3803
  reopenOrder: (order, bridge) => reopen(order, bridge, bookingAccess)
3726
3804
  },
@@ -3728,7 +3806,7 @@ function attendanceOrdersWith(options) {
3728
3806
  kind: TICKET,
3729
3807
  repeatable: true,
3730
3808
  eligibility: (item) => eligible(item, TICKET, options.eventsEnabled),
3731
- openOrder: (item, bridge, beforeCreate) => options.eventsEnabled ? openTicket(item, bridge, now, beforeCreate) : Promise.resolve(NOT_ENABLED),
3809
+ openOrder: (item, bridge, beforeCreate, afterCreate) => options.eventsEnabled ? openTicket(item, bridge, now, beforeCreate, afterCreate) : Promise.resolve(NOT_ENABLED),
3732
3810
  readAccess: ticketAccess,
3733
3811
  reopenOrder: (order, bridge) => reopen(order, bridge, ticketAccess, now)
3734
3812
  }
@@ -3741,7 +3819,7 @@ function eligible(item, kind, enabled) {
3741
3819
  const selection = kind === BOOKING ? item.attendance.booking : item.attendance.ticket;
3742
3820
  return selection ? { eligible: true } : UNSUPPORTED;
3743
3821
  }
3744
- async function openBooking(item, bridge, beforeCreate) {
3822
+ async function openBooking(item, bridge, beforeCreate, afterCreate) {
3745
3823
  if (!eligible(item, BOOKING, true).eligible) return notCreated(ORDER_REFUSED);
3746
3824
  const selected = item.attendance.booking;
3747
3825
  if (selected.slot.serviceId !== item.reference.id || !isNonEmpty3(selected.slot.startDate) || !isNonEmpty3(selected.slot.endDate)) return notCreated(ORDER_REFUSED);
@@ -3755,11 +3833,49 @@ async function openBooking(item, bridge, beforeCreate) {
3755
3833
  if (isRefusal(availability)) return notCreated(attemptRefused(availability));
3756
3834
  const entries = isObject7(availability.body) ? availability.body.availabilityEntries : void 0;
3757
3835
  if (!Array.isArray(entries) || !entries.some((entry) => isObject7(entry) && entry.bookable === true && matchesSlot(entry.slot, selected.slot))) return notCreated(CHANGED);
3758
- if (beforeCreate && !beforeCreate()) return notCreated({ status: "refused", reason: "storageUnavailable" });
3836
+ if (beforeCreate && !beforeCreate(slotGuard(selected.slot))) return notCreated({ status: "refused", reason: "storageUnavailable" });
3759
3837
  const created = await bridge.call("POST", "/bookings/v2/bookings", { booking: { bookedEntity: { slot: selected.slot }, contactDetails: selected.contactDetails, totalParticipants: 1, selectedPaymentOption: "ONLINE", ...selected.formInfo ? { formInfo: selected.formInfo } : {} } });
3760
3838
  if (isRefusal(created)) return creationRefused(created);
3761
3839
  const bookingId = bodyObject(created, "booking")?.id;
3762
- return isNonEmpty3(bookingId) ? bookingCheckout(item, bookingId, bridge) : ORDER_REFUSED;
3840
+ if (!isNonEmpty3(bookingId)) return ORDER_REFUSED;
3841
+ afterCreate?.({ verticalRef: { bookingId } });
3842
+ return bookingCheckout(item, bookingId, bridge);
3843
+ }
3844
+ function slotGuard(slot) {
3845
+ const verticalRef = {};
3846
+ for (const key of ["sessionId", "startDate"]) if (isNonEmpty3(slot[key])) verticalRef[key] = slot[key];
3847
+ const ends = latestInstant(String(slot.endDate));
3848
+ return Number.isFinite(ends) ? { verticalRef, releaseAt: ends + RELEASE_MARGIN_MS } : { verticalRef };
3849
+ }
3850
+ function latestInstant(value) {
3851
+ if (HAS_OFFSET.test(value)) return Date.parse(value);
3852
+ return Date.parse(`${value}Z`) + LATEST_ZONE_MS;
3853
+ }
3854
+ async function resolveBookingOpening(guard, item, bridge, options) {
3855
+ const scope = sameSlot(guard.verticalRef, item?.attendance?.booking?.slot) ? "held" : "unrelated";
3856
+ const bookingId = guard.verticalRef?.bookingId;
3857
+ if (!bookingId || !options.settled) return scope;
3858
+ const released2 = await releaseBooking(bookingId, bridge, options.claim);
3859
+ return released2 === "held" || released2 === "unavailable" && scope === "unrelated" ? scope : released2;
3860
+ }
3861
+ async function releaseBooking(bookingId, bridge, claim) {
3862
+ const read2 = await bridge.call("POST", "/bookings/v2/bookings/query", { query: { filter: { id: { $eq: bookingId } } } });
3863
+ if (isRefusal(read2)) return read2.status === "http" && read2.httpStatus === 404 ? "released" : openingRefused(read2);
3864
+ const rows = isObject7(read2.body) ? read2.body.bookings : void 0;
3865
+ const booking = Array.isArray(rows) ? rows.find((b) => isObject7(b) && b.id === bookingId) : void 0;
3866
+ if (!isObject7(booking)) return "held";
3867
+ if (["CANCELED", "CANCELLED", "DECLINED"].includes(String(booking.status)) || PAYMENT_TAKEN.includes(String(booking.paymentStatus))) return "released";
3868
+ if (booking.status !== "CREATED" || !claim()) return "held";
3869
+ const cancelled = await bridge.call("POST", `/bookings/v2/bookings/${encodeURIComponent(bookingId)}/cancel`, { participantNotification: { notifyParticipants: false }, revision: booking.revision });
3870
+ return isRefusal(cancelled) ? openingRefused(cancelled) : "released";
3871
+ }
3872
+ function openingRefused(refusal) {
3873
+ if (refusal.status === "sessionChanged") return "sessionChanged";
3874
+ return refusal.status === "unavailable" ? "unavailable" : "held";
3875
+ }
3876
+ function sameSlot(guarded, slot) {
3877
+ if (!guarded || !slot) return true;
3878
+ return guarded.sessionId === slot.sessionId && Date.parse(guarded.startDate ?? "") === Date.parse(String(slot.startDate));
3763
3879
  }
3764
3880
  async function bookingCheckout(item, bookingId, bridge) {
3765
3881
  const checkout = await bridge.call("POST", "/ecom/v1/checkouts", { lineItems: [{ quantity: 1, catalogReference: { appId: "13d21c63-b5ec-5912-8397-c3a5ddb27a97", catalogItemId: bookingId } }], channelType: "OTHER_PLATFORM" });
@@ -3788,7 +3904,7 @@ async function bookingAccess(ref, bridge) {
3788
3904
  if (booking.status === "CANCELED" || booking.status === "CANCELLED" || booking.status === "DECLINED") return "none";
3789
3905
  return payment === "PAID" && booking.status === "CONFIRMED" && booking.paymentStatus === "PAID" ? "granted" : "pending";
3790
3906
  }
3791
- async function openTicket(item, bridge, now, beforeCreate) {
3907
+ async function openTicket(item, bridge, now, beforeCreate, afterCreate) {
3792
3908
  if (!eligible(item, TICKET, true).eligible) return notCreated(ORDER_REFUSED);
3793
3909
  const selected = item.attendance.ticket;
3794
3910
  if (!isNonEmpty3(selected.eventId)) return notCreated(ORDER_REFUSED);
@@ -3799,16 +3915,23 @@ async function openTicket(item, bridge, now, beforeCreate) {
3799
3915
  const definitions = isObject7(available.body) ? available.body.definitions : void 0;
3800
3916
  const live = Array.isArray(definitions) ? definitions.find((t) => isObject7(t) && t.id === item.reference.id && t.saleStatus === "SALE_STARTED") : void 0;
3801
3917
  if (!isObject7(live) || !samePrice(live.price, item)) return notCreated(CHANGED);
3802
- if (live.eventId !== selected.eventId || classifyForApple(availableTicketAttendanceOf(bodyObject(read2, "event"), live), item.attendance.currency) !== "appleIap") return notCreated(ORDER_REFUSED);
3803
- if (beforeCreate && !beforeCreate()) return notCreated({ status: "refused", reason: "storageUnavailable" });
3804
- return reserveTicket(item, bridge, now);
3918
+ const event = bodyObject(read2, "event");
3919
+ if (live.eventId !== selected.eventId || classifyForApple(availableTicketAttendanceOf(event, live), item.attendance.currency) !== "appleIap") return notCreated(ORDER_REFUSED);
3920
+ if (beforeCreate && !beforeCreate({ releaseAt: now() + reservationMinutes(event) * MINUTE_MS + RELEASE_MARGIN_MS })) return notCreated({ status: "refused", reason: "storageUnavailable" });
3921
+ return reserveTicket(item, bridge, now, afterCreate);
3922
+ }
3923
+ function reservationMinutes(event) {
3924
+ const registration = isObject7(event?.registration) ? event.registration : void 0;
3925
+ const minutes = isObject7(registration?.tickets) ? registration.tickets.reservationDurationInMinutes : void 0;
3926
+ return typeof minutes === "number" && minutes > 0 ? minutes : DEFAULT_RESERVATION_MINUTES;
3805
3927
  }
3806
- async function reserveTicket(item, bridge, now) {
3928
+ async function reserveTicket(item, bridge, now, afterCreate) {
3807
3929
  const selected = item.attendance.ticket;
3808
3930
  const held = await bridge.call("POST", "/events/v1/checkout/reservations", { eventId: selected.eventId, ticketQuantities: [{ ticketDefinitionId: item.reference.id, quantity: 1 }], ignoreLimits: false, allowHiddenTickets: false });
3809
3931
  if (isRefusal(held)) return creationRefused(held);
3810
3932
  const reservation = held.body;
3811
3933
  if (!isObject7(reservation) || !isNonEmpty3(reservation.id) || !future(reservation.expires, now)) return ORDER_CLOSED;
3934
+ afterCreate?.({ verticalRef: { reservationId: reservation.id }, releaseAt: Date.parse(reservation.expires) + RELEASE_MARGIN_MS });
3812
3935
  if (!heldAsSelected(reservation, item)) return CHANGED;
3813
3936
  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 } });
3814
3937
  if (isRefusal(placed)) return attemptRefused(placed);
@@ -4200,7 +4323,7 @@ function createCheckoutService(opts = {}) {
4200
4323
  const commerce = createIapCommerce({ adapters: [pricingPlanOrders], onChange: () => {
4201
4324
  void svc.pricingPublish();
4202
4325
  } });
4203
- const purchaseCopy = { buy: c.joinCta ?? "Get access", processing: c.pendingNotice ?? "Processing your purchase\u2026", awaitingApproval: "Waiting for approval", unavailable: c.failedNotice ?? "Purchasing is temporarily unavailable.", signInRequired: c.signInFirst ?? "Sign in to join a plan \u2014 memberships belong to a member account.", retry: c.failedNotice ?? "Something went wrong. Try again.", priceChanged: "The price changed. Check it and try again.", support: "We couldn't finish this purchase. Contact support." };
4326
+ const purchaseCopy = { buy: c.joinCta ?? "Buy now", processing: c.pendingNotice ?? "Processing your purchase\u2026", awaitingApproval: "Waiting for approval", unavailable: c.failedNotice ?? "Purchasing is temporarily unavailable.", signInRequired: c.signInFirst ?? "Sign in to join a plan \u2014 memberships belong to a member account.", retry: c.failedNotice ?? "Something went wrong. Try again.", priceChanged: "The price changed. Check it and try again.", support: "We couldn't finish this purchase. Contact support." };
4204
4327
  let catalogRows = [];
4205
4328
  let items = [];
4206
4329
  let started = false;
@@ -1,3 +1,20 @@
1
+ // ../../stdlib/wix-sdk/forms/src/extensions.ts
2
+ var SUBMISSIONS_PATH = "/form-submission-service/v4/submissions";
3
+ function createSubmission(req, opts) {
4
+ if (!req?.submission?.formId) throw new Error("createSubmission: submission.formId is required");
5
+ if (opts?.offline !== "queue") return wixCall("POST", SUBMISSIONS_PATH, req, opts);
6
+ const api = globalThis.himalaya?.wixApi;
7
+ if (!api) return Promise.reject(new Error("@himalaya/wix-forms: host did not install the wixApi bridge"));
8
+ const site = opts.site?.trim();
9
+ const headers = site ? { "wix-site-id": site } : void 0;
10
+ if (!api.offline) return api.call("POST", SUBMISSIONS_PATH, req, headers).then((value) => ({ status: "sent", value }));
11
+ return api.call("POST", SUBMISSIONS_PATH, req, headers, { offline: "queue" });
12
+ }
13
+ function validateFormSubmission(req, opts) {
14
+ if (!req?.submission?.formId) throw new Error("validateFormSubmission: submission.formId is required");
15
+ return wixCall("POST", `${SUBMISSIONS_PATH}/validate`, req, opts);
16
+ }
17
+
1
18
  // ../../stdlib/wix-sdk/forms/src/index.ts
2
19
  function wixCallHeaders(opts) {
3
20
  const site = opts?.site?.trim();
@@ -67,10 +84,12 @@ function getSubmission(id, opts) {
67
84
  );
68
85
  }
69
86
  export {
87
+ createSubmission,
70
88
  getForm,
71
89
  getSubmission,
72
90
  queryForms,
73
91
  querySubmissions,
92
+ validateFormSubmission,
74
93
  wixCall
75
94
  };
76
95
  //# sourceMappingURL=wix-forms.mjs.map