@wix/himalaya-cli 0.1572.0 → 0.1574.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 (103) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-module.d.ts +2 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/message-format.d.ts +59 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/checkout/src/index.d.ts +4 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +1 -1
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-contract.d.ts +2 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/index.d.ts +1 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/one-app-page.d.ts +61 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/social-feed/src/index.d.ts +34 -9
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/checkout.mjs +28 -3
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +3 -3
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +2 -1
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/l10n.mjs +8 -3
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +573 -73
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +3 -3
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-social-feed.mjs +24 -1
  16. package/dist/cli.mjs +2708 -1182
  17. package/dist/preview-assets.generated.bin +0 -0
  18. package/guides/himi-json-output.md +41 -2
  19. package/guides/himi-mcp.md +1 -1
  20. package/guides/himi-test.md +3 -2
  21. package/guides/iap-products.md +1 -1
  22. package/guides/importing-oneapp-translations.md +115 -0
  23. package/guides/index.json +6 -0
  24. package/guides/one-app-section-mappings.md +16 -4
  25. package/guides/one-app-to-himi-app.md +221 -10
  26. package/guides/qa-builds.md +21 -1
  27. package/guides/sdk-reference.json +28 -4
  28. package/guides/templates.md +3 -2
  29. package/guides/testing-himi-apps.md +1 -1
  30. package/guides/webview-page-sdk.md +68 -3
  31. package/package.json +3 -3
  32. package/templates/beauty-salon/dev/index.ts +22 -6
  33. package/templates/beauty-salon/tier5-src/_shared/iap-worker.ts +2 -0
  34. package/templates/beauty-salon/tier5-src/_shared/payment-setup.ts +6 -0
  35. package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +5 -2
  36. package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +5 -2
  37. package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +5 -2
  38. package/templates/beauty-salon-owner/dev/index.ts +22 -6
  39. package/templates/branded-lite/dev/index.ts +22 -6
  40. package/templates/branded-lite/tier5-src/_shared/iap-worker.ts +2 -0
  41. package/templates/branded-lite/tier5-src/_shared/payment-setup.ts +6 -0
  42. package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +5 -2
  43. package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +5 -2
  44. package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +5 -2
  45. package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +5 -2
  46. package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +9 -4
  47. package/templates/community-club/dev/index.ts +22 -6
  48. package/templates/community-club/tier5-src/_shared/iap-worker.ts +2 -0
  49. package/templates/community-club/tier5-src/_shared/payment-setup.ts +6 -0
  50. package/templates/community-club/tier5-src/himi-events-detail/index.ts +9 -4
  51. package/templates/community-club-owner/dev/index.ts +22 -6
  52. package/templates/events-meetups/dev/index.ts +22 -6
  53. package/templates/events-meetups/tier5-src/_shared/iap-worker.ts +2 -0
  54. package/templates/events-meetups/tier5-src/_shared/payment-setup.ts +6 -0
  55. package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +9 -4
  56. package/templates/events-meetups-owner/dev/index.ts +22 -6
  57. package/templates/gym-fitness/dev/index.ts +22 -6
  58. package/templates/gym-fitness/tier5-src/_shared/iap-worker.ts +2 -0
  59. package/templates/gym-fitness/tier5-src/_shared/payment-setup.ts +6 -0
  60. package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +5 -2
  61. package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +5 -2
  62. package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +5 -2
  63. package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +9 -4
  64. package/templates/gym-fitness-owner/dev/index.ts +22 -6
  65. package/templates/himi-chat/dev/index.ts +22 -6
  66. package/templates/nonprofit-cause/dev/index.ts +22 -6
  67. package/templates/nonprofit-cause/tier5-src/_shared/iap-worker.ts +2 -0
  68. package/templates/nonprofit-cause/tier5-src/_shared/payment-setup.ts +6 -0
  69. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +5 -2
  70. package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +9 -4
  71. package/templates/nonprofit-cause-owner/dev/index.ts +22 -6
  72. package/templates/owner-lite/dev/index.ts +22 -6
  73. package/templates/podcast-creator/dev/index.ts +22 -6
  74. package/templates/podcast-creator/tier5-src/_shared/iap-worker.ts +2 -0
  75. package/templates/podcast-creator/tier5-src/_shared/payment-setup.ts +6 -0
  76. package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +5 -2
  77. package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +9 -4
  78. package/templates/podcast-creator-owner/dev/index.ts +22 -6
  79. package/templates/portfolio-creative/dev/index.ts +22 -6
  80. package/templates/portfolio-creative/tier5-src/_shared/iap-worker.ts +2 -0
  81. package/templates/portfolio-creative/tier5-src/_shared/payment-setup.ts +6 -0
  82. package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +5 -2
  83. package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +9 -4
  84. package/templates/portfolio-creative-owner/dev/index.ts +22 -6
  85. package/templates/restaurant/dev/index.ts +22 -6
  86. package/templates/restaurant/tier5-src/_shared/iap-worker.ts +2 -0
  87. package/templates/restaurant/tier5-src/_shared/payment-setup.ts +6 -0
  88. package/templates/restaurant/tier5-src/himi-events-detail/index.ts +9 -4
  89. package/templates/restaurant-owner/dev/index.ts +22 -6
  90. package/templates/retail-store/dev/index.ts +22 -6
  91. package/templates/retail-store/tier5-src/_shared/iap-worker.ts +2 -0
  92. package/templates/retail-store/tier5-src/_shared/payment-setup.ts +6 -0
  93. package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +5 -2
  94. package/templates/retail-store-owner/dev/index.ts +22 -6
  95. package/templates/surface-showcase/dev/index.ts +22 -6
  96. package/templates/yoga-studio/dev/index.ts +22 -6
  97. package/templates/yoga-studio/tier5-src/_shared/iap-worker.ts +2 -0
  98. package/templates/yoga-studio/tier5-src/_shared/payment-setup.ts +6 -0
  99. package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +5 -2
  100. package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +5 -2
  101. package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +5 -2
  102. package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +9 -4
  103. package/templates/yoga-studio-owner/dev/index.ts +22 -6
@@ -1799,15 +1799,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
1799
1799
 
1800
1800
  // Live seed-id enumeration: a published release serves only EXACT screens, so
1801
1801
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
1802
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
1803
- // best-effort (offline build → no baked details, preview still live-resolves).
1802
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
1803
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
1804
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
1805
+ // baked details, preview still live-resolves).
1806
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
1807
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
1808
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
1809
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
1810
+ const oneApp = auth?.visitorSource === "one-app";
1811
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
1812
+ if (clientId && !clientId.startsWith("YOUR_")) {
1813
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
1814
+ return ((await mint.json()) as { access_token?: string }).access_token;
1815
+ }
1816
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
1817
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
1818
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
1819
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
1820
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
1821
+ }
1822
+
1804
1823
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
1805
1824
  try {
1806
1825
  const WIX = "https://www.wixapis.com";
1807
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
1808
- if (!clientId || clientId.startsWith("YOUR_")) return [];
1809
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
1810
- const token = ((await mint.json()) as { access_token?: string }).access_token;
1826
+ const token = await liveSeedToken(WIX);
1811
1827
  if (!token) return [];
1812
1828
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
1813
1829
  const json = (await res.json()) as Record<string, unknown>;
@@ -26721,15 +26721,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
26721
26721
 
26722
26722
  // Live seed-id enumeration: a published release serves only EXACT screens, so
26723
26723
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
26724
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
26725
- // best-effort (offline build → no baked details, preview still live-resolves).
26724
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
26725
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
26726
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
26727
+ // baked details, preview still live-resolves).
26728
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
26729
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
26730
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
26731
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
26732
+ const oneApp = auth?.visitorSource === "one-app";
26733
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
26734
+ if (clientId && !clientId.startsWith("YOUR_")) {
26735
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
26736
+ return ((await mint.json()) as { access_token?: string }).access_token;
26737
+ }
26738
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
26739
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
26740
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
26741
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
26742
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
26743
+ }
26744
+
26726
26745
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
26727
26746
  try {
26728
26747
  const WIX = "https://www.wixapis.com";
26729
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
26730
- if (!clientId || clientId.startsWith("YOUR_")) return [];
26731
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
26732
- const token = ((await mint.json()) as { access_token?: string }).access_token;
26748
+ const token = await liveSeedToken(WIX);
26733
26749
  if (!token) return [];
26734
26750
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
26735
26751
  const json = (await res.json()) as Record<string, unknown>;
@@ -4,6 +4,7 @@
4
4
  // SDK; this only supplies the copy and the hydration reset.
5
5
  import { hostSessionFromGlobal, type IapPriceCopy } from "@himalaya/iap";
6
6
  import type { IapCommerce, IapPurchaseCopy, IapRestoreResult } from "@himalaya/iap-checkout";
7
+ import { paymentSetupMessage } from "./payment-setup.js";
7
8
  import { copyParam, copyTemplate } from "./himi-copy.js";
8
9
 
9
10
  /** Price labels from the screen's copy pack (`<prefix>.priceLoadingText`, …). */
@@ -25,6 +26,7 @@ export function iapPurchaseCopy(prefix: string): IapPurchaseCopy {
25
26
  awaitingApproval: copyParam(`${prefix}.purchaseAwaitingApprovalText`, "Waiting for approval"),
26
27
  unavailable: copyParam(`${prefix}.purchaseTemporarilyUnavailableText`, "Purchasing is temporarily unavailable."),
27
28
  signInRequired: copyParam(`${prefix}.purchaseSignInText`, "Sign in to buy."),
29
+ sitePaymentUnavailable: paymentSetupMessage(prefix),
28
30
  retry: copyParam(`${prefix}.purchaseRetryText`, "Something went wrong. Try again."),
29
31
  priceChanged: copyParam(`${prefix}.purchasePriceChangedText`, "The price changed. Check it and try again."),
30
32
  support: copyParam(`${prefix}.purchaseSupportText`, "We couldn't finish this purchase. Contact support."),
@@ -0,0 +1,6 @@
1
+ import { copyParam } from "./himi-copy.js";
2
+
3
+ /** No provider or country guess: Wix only established that online payment is unavailable. */
4
+ export function paymentSetupMessage(prefix: string): string {
5
+ return copyParam(`${prefix}.paymentSetupUnavailable`, "This site is not accepting online payments. Go back or contact the business for other payment options.");
6
+ }
@@ -1,3 +1,4 @@
1
+ import { paymentSetupMessage } from "../_shared/payment-setup.js";
1
2
  import { offlineWriteMessage, offlineWritesEnabled, withOnlineWrites } from "../_shared/online-actions.js";
2
3
  import { connectivity } from "@himalaya/state";
3
4
  import { defineService as registerService } from "../_shared/collection-service.js";
@@ -6,7 +7,7 @@ import { createRedirectSession } from "@himalaya/wix-redirects";
6
7
  import { open as openUrl } from "@himalaya/open-url";
7
8
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
8
9
  import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
9
- import { activePlanIds, entitlement, payCashierOrder } from "@himalaya/checkout";
10
+ import { activePlanIds, entitlement, isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
10
11
  import { hostSessionFromGlobal, iapPriceFields, type IapCatalogItem } from "@himalaya/iap";
11
12
  import { createIapCommerce, pricingPlanOrders } from "@himalaya/iap-checkout";
12
13
  import { iapPriceCopy, iapPurchaseCopy, resetUnhydratedKeysOnOlderRuntime } from "../_shared/iap-worker.js";
@@ -290,7 +291,9 @@ async function regularJoinMessage(row: PlanRow, reference: { kind: string; id: s
290
291
  if (pay.kind === "cancelled") {
291
292
  return copyParam("plans.joinCancelledMessage", "Payment cancelled — you haven't joined.");
292
293
  }
293
- } catch {
294
+ if (isPaymentSetupFailure(pay)) return paymentSetupMessage("plans");
295
+ } catch (error) {
296
+ if (isPaymentSetupFailure(error)) return paymentSetupMessage("plans");
294
297
  }
295
298
  return copyTemplate("plans.joinOnSiteMessage", "Memberships are purchased on the website — visit the site to join {name}.", { name: row.name });
296
299
  }
@@ -1,3 +1,4 @@
1
+ import { paymentSetupMessage } from "../_shared/payment-setup.js";
1
2
  // Tier-5 bundle: himi-events — event detail.
2
3
  import { calendarDay, formatClock, formatCurrency, formatWeekdayDateTime, formatWeekdayMonthDay, formatTimeZoneLabel } from "../_shared/engine-intl.js";
3
4
  import { defineService as registerService } from "@himalaya/state";
@@ -18,7 +19,7 @@ import {
18
19
  type WixEvent,
19
20
  } from "@himalaya/wix-events";
20
21
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
21
- import { payCashierOrder } from "@himalaya/checkout";
22
+ import { isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
22
23
  import { get, upsert, type DbEntity } from "@himalaya/local-db";
23
24
  import {
24
25
  currentInputId,
@@ -986,16 +987,18 @@ const svc: ReturnType<typeof defineService<S, DetailActions>> = defineService<S,
986
987
  if (pay.kind === "paid") result = { ...s, ticketSheetOpen: false, snackbarMessage: detailCopy("event.ticketIssued", "You're in — your ticket is confirmed.") };
987
988
  else if (pay.kind === "handoff") result = { ...s, ticketSheetOpen: false, snackbarMessage: detailCopy("event.checkoutOpened", "Complete checkout in the browser to get your tickets.") };
988
989
  else if (pay.kind === "cancelled") result = { ...s, snackbarMessage: detailCopy("event.ticketCancelled", "Payment cancelled — no ticket was issued.") };
990
+ else if (isPaymentSetupFailure(pay)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
989
991
  else throw new Error("Payment could not be completed");
990
992
  }
991
993
  }
992
994
  }
993
- } catch {
995
+ } catch (error) {
996
+ if (isPaymentSetupFailure(error)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
994
997
  try {
995
998
  // A public event page is not pinned to this selection or price. Only
996
999
  // continue in hosted checkout when a reservation already holds it.
997
1000
  const params = reservationId ? { reservationId } : undefined;
998
- if (params) {
1001
+ if (params && !result) {
999
1002
  const redirect = await createRedirectSession({ eventsCheckout: params });
1000
1003
  const url = redirect.redirectSession?.fullUrl;
1001
1004
  if (url) {
@@ -1003,7 +1006,9 @@ const svc: ReturnType<typeof defineService<S, DetailActions>> = defineService<S,
1003
1006
  result = { ...s, ticketSheetOpen: false, snackbarMessage: opened.opened ? detailCopy("event.checkoutOpened", "Complete checkout in the browser to get your tickets.") : detailCopy("event.registrationOpenFailed", "Could not open the registration page.") };
1004
1007
  }
1005
1008
  }
1006
- } catch { /* report below */ }
1009
+ } catch (error) {
1010
+ if (isPaymentSetupFailure(error)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
1011
+ }
1007
1012
  if (!result) result = { ...s, snackbarMessage: detailCopy("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") };
1008
1013
  } finally { ticketCheckoutInFlight = false; }
1009
1014
  return derive(result!);
@@ -82115,15 +82115,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
82115
82115
 
82116
82116
  // Live seed-id enumeration: a published release serves only EXACT screens, so
82117
82117
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
82118
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
82119
- // best-effort (offline build → no baked details, preview still live-resolves).
82118
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
82119
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
82120
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
82121
+ // baked details, preview still live-resolves).
82122
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
82123
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
82124
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
82125
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
82126
+ const oneApp = auth?.visitorSource === "one-app";
82127
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
82128
+ if (clientId && !clientId.startsWith("YOUR_")) {
82129
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
82130
+ return ((await mint.json()) as { access_token?: string }).access_token;
82131
+ }
82132
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
82133
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
82134
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
82135
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
82136
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
82137
+ }
82138
+
82120
82139
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
82121
82140
  try {
82122
82141
  const WIX = "https://www.wixapis.com";
82123
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
82124
- if (!clientId || clientId.startsWith("YOUR_")) return [];
82125
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
82126
- const token = ((await mint.json()) as { access_token?: string }).access_token;
82142
+ const token = await liveSeedToken(WIX);
82127
82143
  if (!token) return [];
82128
82144
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
82129
82145
  const json = (await res.json()) as Record<string, unknown>;
@@ -93008,15 +93008,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
93008
93008
 
93009
93009
  // Live seed-id enumeration: a published release serves only EXACT screens, so
93010
93010
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
93011
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
93012
- // best-effort (offline build → no baked details, preview still live-resolves).
93011
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
93012
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
93013
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
93014
+ // baked details, preview still live-resolves).
93015
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
93016
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
93017
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
93018
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
93019
+ const oneApp = auth?.visitorSource === "one-app";
93020
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
93021
+ if (clientId && !clientId.startsWith("YOUR_")) {
93022
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
93023
+ return ((await mint.json()) as { access_token?: string }).access_token;
93024
+ }
93025
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
93026
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
93027
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
93028
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
93029
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
93030
+ }
93031
+
93013
93032
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
93014
93033
  try {
93015
93034
  const WIX = "https://www.wixapis.com";
93016
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
93017
- if (!clientId || clientId.startsWith("YOUR_")) return [];
93018
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
93019
- const token = ((await mint.json()) as { access_token?: string }).access_token;
93035
+ const token = await liveSeedToken(WIX);
93020
93036
  if (!token) return [];
93021
93037
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
93022
93038
  const json = (await res.json()) as Record<string, unknown>;
@@ -26770,15 +26770,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
26770
26770
 
26771
26771
  // Live seed-id enumeration: a published release serves only EXACT screens, so
26772
26772
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
26773
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
26774
- // best-effort (offline build → no baked details, preview still live-resolves).
26773
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
26774
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
26775
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
26776
+ // baked details, preview still live-resolves).
26777
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
26778
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
26779
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
26780
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
26781
+ const oneApp = auth?.visitorSource === "one-app";
26782
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
26783
+ if (clientId && !clientId.startsWith("YOUR_")) {
26784
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
26785
+ return ((await mint.json()) as { access_token?: string }).access_token;
26786
+ }
26787
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
26788
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
26789
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
26790
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
26791
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
26792
+ }
26793
+
26775
26794
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
26776
26795
  try {
26777
26796
  const WIX = "https://www.wixapis.com";
26778
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
26779
- if (!clientId || clientId.startsWith("YOUR_")) return [];
26780
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
26781
- const token = ((await mint.json()) as { access_token?: string }).access_token;
26797
+ const token = await liveSeedToken(WIX);
26782
26798
  if (!token) return [];
26783
26799
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
26784
26800
  const json = (await res.json()) as Record<string, unknown>;
@@ -4,6 +4,7 @@
4
4
  // SDK; this only supplies the copy and the hydration reset.
5
5
  import { hostSessionFromGlobal, type IapPriceCopy } from "@himalaya/iap";
6
6
  import type { IapCommerce, IapPurchaseCopy, IapRestoreResult } from "@himalaya/iap-checkout";
7
+ import { paymentSetupMessage } from "./payment-setup.js";
7
8
  import { copyParam, copyTemplate } from "./himi-copy.js";
8
9
 
9
10
  /** Price labels from the screen's copy pack (`<prefix>.priceLoadingText`, …). */
@@ -25,6 +26,7 @@ export function iapPurchaseCopy(prefix: string): IapPurchaseCopy {
25
26
  awaitingApproval: copyParam(`${prefix}.purchaseAwaitingApprovalText`, "Waiting for approval"),
26
27
  unavailable: copyParam(`${prefix}.purchaseTemporarilyUnavailableText`, "Purchasing is temporarily unavailable."),
27
28
  signInRequired: copyParam(`${prefix}.purchaseSignInText`, "Sign in to buy."),
29
+ sitePaymentUnavailable: paymentSetupMessage(prefix),
28
30
  retry: copyParam(`${prefix}.purchaseRetryText`, "Something went wrong. Try again."),
29
31
  priceChanged: copyParam(`${prefix}.purchasePriceChangedText`, "The price changed. Check it and try again."),
30
32
  support: copyParam(`${prefix}.purchaseSupportText`, "We couldn't finish this purchase. Contact support."),
@@ -0,0 +1,6 @@
1
+ import { copyParam } from "./himi-copy.js";
2
+
3
+ /** No provider or country guess: Wix only established that online payment is unavailable. */
4
+ export function paymentSetupMessage(prefix: string): string {
5
+ return copyParam(`${prefix}.paymentSetupUnavailable`, "This site is not accepting online payments. Go back or contact the business for other payment options.");
6
+ }
@@ -1,3 +1,4 @@
1
+ import { paymentSetupMessage } from "../_shared/payment-setup.js";
1
2
  import { offlineWriteMessage, offlineWritesEnabled, withOnlineWrites } from "../_shared/online-actions.js";
2
3
  import { connectivity } from "@himalaya/state";
3
4
  import { defineService as registerService } from "../_shared/collection-service.js";
@@ -6,7 +7,7 @@ import { createRedirectSession } from "@himalaya/wix-redirects";
6
7
  import { open as openUrl } from "@himalaya/open-url";
7
8
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
8
9
  import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
9
- import { activePlanIds, entitlement, payCashierOrder } from "@himalaya/checkout";
10
+ import { activePlanIds, entitlement, isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
10
11
  import { hostSessionFromGlobal, iapPriceFields, type IapCatalogItem } from "@himalaya/iap";
11
12
  import { createIapCommerce, pricingPlanOrders } from "@himalaya/iap-checkout";
12
13
  import { iapPriceCopy, iapPurchaseCopy, resetUnhydratedKeysOnOlderRuntime } from "../_shared/iap-worker.js";
@@ -290,7 +291,9 @@ async function regularJoinMessage(row: PlanRow, reference: { kind: string; id: s
290
291
  if (pay.kind === "cancelled") {
291
292
  return copyParam("plans.joinCancelledMessage", "Payment cancelled — you haven't joined.");
292
293
  }
293
- } catch {
294
+ if (isPaymentSetupFailure(pay)) return paymentSetupMessage("plans");
295
+ } catch (error) {
296
+ if (isPaymentSetupFailure(error)) return paymentSetupMessage("plans");
294
297
  }
295
298
  return copyTemplate("plans.joinOnSiteMessage", "Memberships are purchased on the website — visit the site to join {name}.", { name: row.name });
296
299
  }
@@ -1,3 +1,4 @@
1
+ import { paymentSetupMessage } from "../_shared/payment-setup.js";
1
2
  // Tier-5 bundle: himi-events — event detail.
2
3
  import { calendarDay, formatClock, formatCurrency, formatWeekdayDateTime, formatWeekdayMonthDay, formatTimeZoneLabel } from "../_shared/engine-intl.js";
3
4
  import { defineService as registerService } from "@himalaya/state";
@@ -18,7 +19,7 @@ import {
18
19
  type WixEvent,
19
20
  } from "@himalaya/wix-events";
20
21
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
21
- import { payCashierOrder } from "@himalaya/checkout";
22
+ import { isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
22
23
  import { get, upsert, type DbEntity } from "@himalaya/local-db";
23
24
  import {
24
25
  currentInputId,
@@ -986,16 +987,18 @@ const svc: ReturnType<typeof defineService<S, DetailActions>> = defineService<S,
986
987
  if (pay.kind === "paid") result = { ...s, ticketSheetOpen: false, snackbarMessage: detailCopy("event.ticketIssued", "You're in — your ticket is confirmed.") };
987
988
  else if (pay.kind === "handoff") result = { ...s, ticketSheetOpen: false, snackbarMessage: detailCopy("event.checkoutOpened", "Complete checkout in the browser to get your tickets.") };
988
989
  else if (pay.kind === "cancelled") result = { ...s, snackbarMessage: detailCopy("event.ticketCancelled", "Payment cancelled — no ticket was issued.") };
990
+ else if (isPaymentSetupFailure(pay)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
989
991
  else throw new Error("Payment could not be completed");
990
992
  }
991
993
  }
992
994
  }
993
- } catch {
995
+ } catch (error) {
996
+ if (isPaymentSetupFailure(error)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
994
997
  try {
995
998
  // A public event page is not pinned to this selection or price. Only
996
999
  // continue in hosted checkout when a reservation already holds it.
997
1000
  const params = reservationId ? { reservationId } : undefined;
998
- if (params) {
1001
+ if (params && !result) {
999
1002
  const redirect = await createRedirectSession({ eventsCheckout: params });
1000
1003
  const url = redirect.redirectSession?.fullUrl;
1001
1004
  if (url) {
@@ -1003,7 +1006,9 @@ const svc: ReturnType<typeof defineService<S, DetailActions>> = defineService<S,
1003
1006
  result = { ...s, ticketSheetOpen: false, snackbarMessage: opened.opened ? detailCopy("event.checkoutOpened", "Complete checkout in the browser to get your tickets.") : detailCopy("event.registrationOpenFailed", "Could not open the registration page.") };
1004
1007
  }
1005
1008
  }
1006
- } catch { /* report below */ }
1009
+ } catch (error) {
1010
+ if (isPaymentSetupFailure(error)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
1011
+ }
1007
1012
  if (!result) result = { ...s, snackbarMessage: detailCopy("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") };
1008
1013
  } finally { ticketCheckoutInFlight = false; }
1009
1014
  return derive(result!);
@@ -85003,15 +85003,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
85003
85003
 
85004
85004
  // Live seed-id enumeration: a published release serves only EXACT screens, so
85005
85005
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
85006
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
85007
- // best-effort (offline build → no baked details, preview still live-resolves).
85006
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
85007
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
85008
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
85009
+ // baked details, preview still live-resolves).
85010
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
85011
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
85012
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
85013
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
85014
+ const oneApp = auth?.visitorSource === "one-app";
85015
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
85016
+ if (clientId && !clientId.startsWith("YOUR_")) {
85017
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
85018
+ return ((await mint.json()) as { access_token?: string }).access_token;
85019
+ }
85020
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
85021
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
85022
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
85023
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
85024
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
85025
+ }
85026
+
85008
85027
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
85009
85028
  try {
85010
85029
  const WIX = "https://www.wixapis.com";
85011
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
85012
- if (!clientId || clientId.startsWith("YOUR_")) return [];
85013
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
85014
- const token = ((await mint.json()) as { access_token?: string }).access_token;
85030
+ const token = await liveSeedToken(WIX);
85015
85031
  if (!token) return [];
85016
85032
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
85017
85033
  const json = (await res.json()) as Record<string, unknown>;
@@ -36114,15 +36114,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
36114
36114
 
36115
36115
  // Live seed-id enumeration: a published release serves only EXACT screens, so
36116
36116
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
36117
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
36118
- // best-effort (offline build → no baked details, preview still live-resolves).
36117
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
36118
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
36119
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
36120
+ // baked details, preview still live-resolves).
36121
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
36122
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
36123
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
36124
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
36125
+ const oneApp = auth?.visitorSource === "one-app";
36126
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
36127
+ if (clientId && !clientId.startsWith("YOUR_")) {
36128
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
36129
+ return ((await mint.json()) as { access_token?: string }).access_token;
36130
+ }
36131
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
36132
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
36133
+ const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
36134
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
36135
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
36136
+ }
36137
+
36119
36138
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
36120
36139
  try {
36121
36140
  const WIX = "https://www.wixapis.com";
36122
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
36123
- if (!clientId || clientId.startsWith("YOUR_")) return [];
36124
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
36125
- const token = ((await mint.json()) as { access_token?: string }).access_token;
36141
+ const token = await liveSeedToken(WIX);
36126
36142
  if (!token) return [];
36127
36143
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
36128
36144
  const json = (await res.json()) as Record<string, unknown>;
@@ -4,6 +4,7 @@
4
4
  // SDK; this only supplies the copy and the hydration reset.
5
5
  import { hostSessionFromGlobal, type IapPriceCopy } from "@himalaya/iap";
6
6
  import type { IapCommerce, IapPurchaseCopy, IapRestoreResult } from "@himalaya/iap-checkout";
7
+ import { paymentSetupMessage } from "./payment-setup.js";
7
8
  import { copyParam, copyTemplate } from "./himi-copy.js";
8
9
 
9
10
  /** Price labels from the screen's copy pack (`<prefix>.priceLoadingText`, …). */
@@ -25,6 +26,7 @@ export function iapPurchaseCopy(prefix: string): IapPurchaseCopy {
25
26
  awaitingApproval: copyParam(`${prefix}.purchaseAwaitingApprovalText`, "Waiting for approval"),
26
27
  unavailable: copyParam(`${prefix}.purchaseTemporarilyUnavailableText`, "Purchasing is temporarily unavailable."),
27
28
  signInRequired: copyParam(`${prefix}.purchaseSignInText`, "Sign in to buy."),
29
+ sitePaymentUnavailable: paymentSetupMessage(prefix),
28
30
  retry: copyParam(`${prefix}.purchaseRetryText`, "Something went wrong. Try again."),
29
31
  priceChanged: copyParam(`${prefix}.purchasePriceChangedText`, "The price changed. Check it and try again."),
30
32
  support: copyParam(`${prefix}.purchaseSupportText`, "We couldn't finish this purchase. Contact support."),
@@ -0,0 +1,6 @@
1
+ import { copyParam } from "./himi-copy.js";
2
+
3
+ /** No provider or country guess: Wix only established that online payment is unavailable. */
4
+ export function paymentSetupMessage(prefix: string): string {
5
+ return copyParam(`${prefix}.paymentSetupUnavailable`, "This site is not accepting online payments. Go back or contact the business for other payment options.");
6
+ }
@@ -1,3 +1,4 @@
1
+ import { paymentSetupMessage } from "../_shared/payment-setup.js";
1
2
  import { withOnlineWrites } from "../_shared/online-actions.js";
2
3
  import { defineService as registerState } from "@himalaya/state";
3
4
  import { getStoreProduct } from "../_shared/himi-store.js";
@@ -7,7 +8,7 @@ import { withIapPresentation } from "../_shared/iap-presentation.js";
7
8
  import { type IapCommerce, classifyCart } from "@himalaya/iap-checkout";
8
9
  import { addCouponToCurrentCart, calculateCurrentCart, createCheckoutFromCurrentCart, getCurrentCart, removeCouponFromCurrentCart, removeLineItemsFromCurrentCart, updateLineItemsQuantity, type WixCartDetail, type WixCartLineItemDetail } from "@himalaya/wix-ecom";
9
10
  import { createRedirectSession } from "@himalaya/wix-redirects";
10
- import { payCashierOrder } from "@himalaya/checkout";
11
+ import { isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
11
12
  import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
12
13
  import { formatCurrency } from "../_shared/engine-intl.js";
13
14
 
@@ -574,8 +575,10 @@ const svc = defineService<State, {
574
575
  // only confirmed once it lands, so the cart must survive a bail-out.
575
576
  return derive({ ...state, checkoutHint: copyParam("cart.checkoutOpenedMessage", "Checkout opened.") });
576
577
  }
578
+ if (isPaymentSetupFailure(pay)) return derive({ ...state, checkoutHint: paymentSetupMessage("cart") });
577
579
  return derive({ ...state, checkoutHint: copyParam("cart.checkoutFailedMessage", "Checkout could not start.") });
578
- } catch {
580
+ } catch (error) {
581
+ if (isPaymentSetupFailure(error)) return derive({ ...state, checkoutHint: paymentSetupMessage("cart") });
579
582
  return derive({ ...state, checkoutHint: copyParam("cart.checkoutFailedMessage", "Checkout could not start.") });
580
583
  }
581
584
  },
@@ -1,3 +1,4 @@
1
+ import { paymentSetupMessage } from "../_shared/payment-setup.js";
1
2
  // Tier-5 bundle: himi-events — event detail.
2
3
  import { calendarDay, formatClock, formatCurrency, formatWeekdayDateTime, formatWeekdayMonthDay, formatTimeZoneLabel } from "../_shared/engine-intl.js";
3
4
  import { defineService as registerService } from "@himalaya/state";
@@ -18,7 +19,7 @@ import {
18
19
  type WixEvent,
19
20
  } from "@himalaya/wix-events";
20
21
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
21
- import { payCashierOrder } from "@himalaya/checkout";
22
+ import { isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
22
23
  import { get, upsert, type DbEntity } from "@himalaya/local-db";
23
24
  import {
24
25
  currentInputId,
@@ -986,16 +987,18 @@ const svc: ReturnType<typeof defineService<S, DetailActions>> = defineService<S,
986
987
  if (pay.kind === "paid") result = { ...s, ticketSheetOpen: false, snackbarMessage: detailCopy("event.ticketIssued", "You're in — your ticket is confirmed.") };
987
988
  else if (pay.kind === "handoff") result = { ...s, ticketSheetOpen: false, snackbarMessage: detailCopy("event.checkoutOpened", "Complete checkout in the browser to get your tickets.") };
988
989
  else if (pay.kind === "cancelled") result = { ...s, snackbarMessage: detailCopy("event.ticketCancelled", "Payment cancelled — no ticket was issued.") };
990
+ else if (isPaymentSetupFailure(pay)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
989
991
  else throw new Error("Payment could not be completed");
990
992
  }
991
993
  }
992
994
  }
993
- } catch {
995
+ } catch (error) {
996
+ if (isPaymentSetupFailure(error)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
994
997
  try {
995
998
  // A public event page is not pinned to this selection or price. Only
996
999
  // continue in hosted checkout when a reservation already holds it.
997
1000
  const params = reservationId ? { reservationId } : undefined;
998
- if (params) {
1001
+ if (params && !result) {
999
1002
  const redirect = await createRedirectSession({ eventsCheckout: params });
1000
1003
  const url = redirect.redirectSession?.fullUrl;
1001
1004
  if (url) {
@@ -1003,7 +1006,9 @@ const svc: ReturnType<typeof defineService<S, DetailActions>> = defineService<S,
1003
1006
  result = { ...s, ticketSheetOpen: false, snackbarMessage: opened.opened ? detailCopy("event.checkoutOpened", "Complete checkout in the browser to get your tickets.") : detailCopy("event.registrationOpenFailed", "Could not open the registration page.") };
1004
1007
  }
1005
1008
  }
1006
- } catch { /* report below */ }
1009
+ } catch (error) {
1010
+ if (isPaymentSetupFailure(error)) result = { ...s, snackbarMessage: paymentSetupMessage("event") };
1011
+ }
1007
1012
  if (!result) result = { ...s, snackbarMessage: detailCopy("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") };
1008
1013
  } finally { ticketCheckoutInFlight = false; }
1009
1014
  return derive(result!);