@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
@@ -86711,15 +86711,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
86711
86711
 
86712
86712
  // Live seed-id enumeration: a published release serves only EXACT screens, so
86713
86713
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
86714
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
86715
- // best-effort (offline build → no baked details, preview still live-resolves).
86714
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
86715
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
86716
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
86717
+ // baked details, preview still live-resolves).
86718
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
86719
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
86720
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
86721
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
86722
+ const oneApp = auth?.visitorSource === "one-app";
86723
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
86724
+ if (clientId && !clientId.startsWith("YOUR_")) {
86725
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
86726
+ return ((await mint.json()) as { access_token?: string }).access_token;
86727
+ }
86728
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
86729
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
86730
+ 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" });
86731
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
86732
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
86733
+ }
86734
+
86716
86735
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
86717
86736
  try {
86718
86737
  const WIX = "https://www.wixapis.com";
86719
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
86720
- if (!clientId || clientId.startsWith("YOUR_")) return [];
86721
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
86722
- const token = ((await mint.json()) as { access_token?: string }).access_token;
86738
+ const token = await liveSeedToken(WIX);
86723
86739
  if (!token) return [];
86724
86740
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
86725
86741
  const json = (await res.json()) as Record<string, unknown>;
@@ -26773,15 +26773,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
26773
26773
 
26774
26774
  // Live seed-id enumeration: a published release serves only EXACT screens, so
26775
26775
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
26776
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
26777
- // best-effort (offline build → no baked details, preview still live-resolves).
26776
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
26777
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
26778
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
26779
+ // baked details, preview still live-resolves).
26780
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
26781
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
26782
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
26783
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
26784
+ const oneApp = auth?.visitorSource === "one-app";
26785
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
26786
+ if (clientId && !clientId.startsWith("YOUR_")) {
26787
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
26788
+ return ((await mint.json()) as { access_token?: string }).access_token;
26789
+ }
26790
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
26791
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
26792
+ 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" });
26793
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
26794
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
26795
+ }
26796
+
26778
26797
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
26779
26798
  try {
26780
26799
  const WIX = "https://www.wixapis.com";
26781
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
26782
- if (!clientId || clientId.startsWith("YOUR_")) return [];
26783
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
26784
- const token = ((await mint.json()) as { access_token?: string }).access_token;
26800
+ const token = await liveSeedToken(WIX);
26785
26801
  if (!token) return [];
26786
26802
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
26787
26803
  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
  // 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!);
@@ -90719,15 +90719,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
90719
90719
 
90720
90720
  // Live seed-id enumeration: a published release serves only EXACT screens, so
90721
90721
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
90722
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
90723
- // best-effort (offline build → no baked details, preview still live-resolves).
90722
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
90723
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
90724
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
90725
+ // baked details, preview still live-resolves).
90726
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
90727
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
90728
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
90729
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
90730
+ const oneApp = auth?.visitorSource === "one-app";
90731
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
90732
+ if (clientId && !clientId.startsWith("YOUR_")) {
90733
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
90734
+ return ((await mint.json()) as { access_token?: string }).access_token;
90735
+ }
90736
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
90737
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
90738
+ 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" });
90739
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
90740
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
90741
+ }
90742
+
90724
90743
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
90725
90744
  try {
90726
90745
  const WIX = "https://www.wixapis.com";
90727
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
90728
- if (!clientId || clientId.startsWith("YOUR_")) return [];
90729
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
90730
- const token = ((await mint.json()) as { access_token?: string }).access_token;
90746
+ const token = await liveSeedToken(WIX);
90731
90747
  if (!token) return [];
90732
90748
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
90733
90749
  const json = (await res.json()) as Record<string, unknown>;
@@ -25622,15 +25622,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
25622
25622
 
25623
25623
  // Live seed-id enumeration: a published release serves only EXACT screens, so
25624
25624
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
25625
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
25626
- // best-effort (offline build → no baked details, preview still live-resolves).
25625
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
25626
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
25627
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
25628
+ // baked details, preview still live-resolves).
25629
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
25630
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
25631
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
25632
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
25633
+ const oneApp = auth?.visitorSource === "one-app";
25634
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
25635
+ if (clientId && !clientId.startsWith("YOUR_")) {
25636
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
25637
+ return ((await mint.json()) as { access_token?: string }).access_token;
25638
+ }
25639
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
25640
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
25641
+ 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" });
25642
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
25643
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
25644
+ }
25645
+
25627
25646
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
25628
25647
  try {
25629
25648
  const WIX = "https://www.wixapis.com";
25630
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
25631
- if (!clientId || clientId.startsWith("YOUR_")) return [];
25632
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
25633
- const token = ((await mint.json()) as { access_token?: string }).access_token;
25649
+ const token = await liveSeedToken(WIX);
25634
25650
  if (!token) return [];
25635
25651
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
25636
25652
  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
  },
@@ -80984,15 +80984,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
80984
80984
 
80985
80985
  // Live seed-id enumeration: a published release serves only EXACT screens, so
80986
80986
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
80987
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
80988
- // best-effort (offline build → no baked details, preview still live-resolves).
80987
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
80988
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
80989
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
80990
+ // baked details, preview still live-resolves).
80991
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
80992
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
80993
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
80994
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
80995
+ const oneApp = auth?.visitorSource === "one-app";
80996
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
80997
+ if (clientId && !clientId.startsWith("YOUR_")) {
80998
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
80999
+ return ((await mint.json()) as { access_token?: string }).access_token;
81000
+ }
81001
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
81002
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
81003
+ 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" });
81004
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
81005
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
81006
+ }
81007
+
80989
81008
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
80990
81009
  try {
80991
81010
  const WIX = "https://www.wixapis.com";
80992
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
80993
- if (!clientId || clientId.startsWith("YOUR_")) return [];
80994
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
80995
- const token = ((await mint.json()) as { access_token?: string }).access_token;
81011
+ const token = await liveSeedToken(WIX);
80996
81012
  if (!token) return [];
80997
81013
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
80998
81014
  const json = (await res.json()) as Record<string, unknown>;
@@ -626,15 +626,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
626
626
 
627
627
  // Live seed-id enumeration: a published release serves only EXACT screens, so
628
628
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
629
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
630
- // best-effort (offline build → no baked details, preview still live-resolves).
629
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
630
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
631
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
632
+ // baked details, preview still live-resolves).
633
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
634
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
635
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
636
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
637
+ const oneApp = auth?.visitorSource === "one-app";
638
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
639
+ if (clientId && !clientId.startsWith("YOUR_")) {
640
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
641
+ return ((await mint.json()) as { access_token?: string }).access_token;
642
+ }
643
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
644
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
645
+ 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" });
646
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
647
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
648
+ }
649
+
631
650
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
632
651
  try {
633
652
  const WIX = "https://www.wixapis.com";
634
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
635
- if (!clientId || clientId.startsWith("YOUR_")) return [];
636
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
637
- const token = ((await mint.json()) as { access_token?: string }).access_token;
653
+ const token = await liveSeedToken(WIX);
638
654
  if (!token) return [];
639
655
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
640
656
  const json = (await res.json()) as Record<string, unknown>;
@@ -37400,15 +37400,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
37400
37400
 
37401
37401
  // Live seed-id enumeration: a published release serves only EXACT screens, so
37402
37402
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
37403
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
37404
- // best-effort (offline build → no baked details, preview still live-resolves).
37403
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
37404
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
37405
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
37406
+ // baked details, preview still live-resolves).
37407
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
37408
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
37409
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
37410
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
37411
+ const oneApp = auth?.visitorSource === "one-app";
37412
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
37413
+ if (clientId && !clientId.startsWith("YOUR_")) {
37414
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
37415
+ return ((await mint.json()) as { access_token?: string }).access_token;
37416
+ }
37417
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
37418
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
37419
+ 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" });
37420
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
37421
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
37422
+ }
37423
+
37405
37424
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
37406
37425
  try {
37407
37426
  const WIX = "https://www.wixapis.com";
37408
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
37409
- if (!clientId || clientId.startsWith("YOUR_")) return [];
37410
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
37411
- const token = ((await mint.json()) as { access_token?: string }).access_token;
37427
+ const token = await liveSeedToken(WIX);
37412
37428
  if (!token) return [];
37413
37429
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
37414
37430
  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, offlineWritesEnabled } from "../_shared/online-actions.js";
2
3
  // Tier-5 bundle: himi-booking — availability and member booking.
3
4
  import { defineService as registerService, navigate } from "@himalaya/state";
@@ -9,7 +10,7 @@ import { dispatch } from "@himalaya/dispatch";
9
10
  import { bookSchedule, bookSlot, getService, queryServiceAvailability, registerToWaitlist, type WixBookingSlotFull, type WixSelectedPaymentOption, type WixService } from "@himalaya/wix-bookings";
10
11
  import { createCheckout, createOrder } from "@himalaya/wix-ecom";
11
12
  import { createRedirectSession, type WixSlot } from "@himalaya/wix-redirects";
12
- import { payCashierOrder } from "@himalaya/checkout";
13
+ import { isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
13
14
  import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
14
15
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
15
16
  import { displayName, getMyData, type WixMyData } from "@himalaya/wix-users";
@@ -1587,10 +1588,12 @@ async function bookSelectedIn(s: S): Promise<S> {
1587
1588
  ? copyParam("time.coursePaymentCancelled", "Payment cancelled — your course booking wasn't confirmed. Try again.")
1588
1589
  : copyParam("time.paymentCancelled", "Payment cancelled — your booking wasn't confirmed. Pick a time to try again.") });
1589
1590
  }
1591
+ if (isPaymentSetupFailure(pay)) return derive({ ...s, bookingInFlight: false, message: paymentSetupMessage("time") });
1590
1592
  return derive({ ...s, bookingInFlight: false, message: s.isCourse
1591
1593
  ? copyParam("time.coursePaymentFailed", "Payment couldn't be completed. Try again.")
1592
1594
  : copyParam("time.paymentFailed", "Payment couldn't be completed. Pick another time or try again.") });
1593
- } catch {
1595
+ } catch (error) {
1596
+ if (isPaymentSetupFailure(error)) return derive({ ...s, bookingInFlight: false, message: paymentSetupMessage("time") });
1594
1597
  return derive({ ...s, bookingInFlight: false, message: s.isCourse
1595
1598
  ? copyParam("time.courseCheckoutFailed", "Checkout could not start. Try again.")
1596
1599
  : copyParam("time.checkoutFailed", "Checkout could not start. Pick another time or try again.") });
@@ -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
  import { dispatch } from "@himalaya/dispatch";
2
3
  import { memberAccess, assertMemberAccess } from "../_shared/member-access.js";
3
4
  import { offlineWriteMessage, withOnlineWrites } from "../_shared/online-actions.js";
@@ -42,7 +43,7 @@ import { getMyMember } from "@himalaya/wix-members";
42
43
  import { session as wixPlatformSession } from "@himalaya/wix-platform";
43
44
  import { cleanTitle, initials } from "../_shared/himi-text.js";
44
45
  import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
45
- import { payCashierOrder } from "@himalaya/checkout";
46
+ import { isPaymentSetupFailure, payCashierOrder } from "@himalaya/checkout";
46
47
  import { formatCurrency } from "../_shared/engine-intl.js";
47
48
  import { iapPriceFields, onlineProgramItem, type IapCatalogItem, type IapPollDirective, type IapPriceFields } from "@himalaya/iap";
48
49
  import { createIapCommerce, onlineProgramOrders, type IapPurchaseFields } from "@himalaya/iap-checkout";
@@ -251,9 +252,11 @@ async function enrollmentMessage(id: string, name: string, guards: CommerceGuard
251
252
  : copyTemplate("program.joinedMessage", "You're enrolled in {name}.", { name });
252
253
  if (pay.kind === "handoff") return "";
253
254
  if (pay.kind === "cancelled") return copyParam("program.joinCancelledMessage", "Payment cancelled — you haven't enrolled.");
254
- } catch {
255
+ if (isPaymentSetupFailure(pay)) return paymentSetupMessage("program");
256
+ } catch (error) {
255
257
  if (!connectivity().online) return offlineWriteMessage;
256
258
  if (preparationWithdrawn) return blocked();
259
+ if (isPaymentSetupFailure(error)) return paymentSetupMessage("program");
257
260
  // fall through to the site-directing message
258
261
  }
259
262
  return copyTemplate("program.joinOnSiteMessage", "Enrolment happens on the website — visit the site to join {name}.", { name });
@@ -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!);
@@ -82114,15 +82114,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
82114
82114
 
82115
82115
  // Live seed-id enumeration: a published release serves only EXACT screens, so
82116
82116
  // `himi push` bakes each templated detail route's CURRENT catalog ids as exact
82117
- // screens via `seedIds`. Anonymous visitor rung against this app's own clientId;
82118
- // best-effort (offline build → no baked details, preview still live-resolves).
82117
+ // screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
82118
+ // for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
82119
+ // no client), that site's One App visitor instance. Best-effort (offline build → no
82120
+ // baked details, preview still live-resolves).
82121
+ async function liveSeedToken(WIX: string): Promise<string | undefined> {
82122
+ const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
82123
+ // A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
82124
+ // even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
82125
+ const oneApp = auth?.visitorSource === "one-app";
82126
+ const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
82127
+ if (clientId && !clientId.startsWith("YOUR_")) {
82128
+ const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
82129
+ return ((await mint.json()) as { access_token?: string }).access_token;
82130
+ }
82131
+ const msid = oneApp ? auth?.metaSiteId ?? "" : "";
82132
+ if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
82133
+ 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" });
82134
+ const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
82135
+ return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
82136
+ }
82137
+
82119
82138
  async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
82120
82139
  try {
82121
82140
  const WIX = "https://www.wixapis.com";
82122
- const clientId = process.env.WIX_CLIENT_ID ?? (config as { auth?: { config?: { clientId?: string } } }).auth?.config?.clientId ?? "";
82123
- if (!clientId || clientId.startsWith("YOUR_")) return [];
82124
- const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
82125
- const token = ((await mint.json()) as { access_token?: string }).access_token;
82141
+ const token = await liveSeedToken(WIX);
82126
82142
  if (!token) return [];
82127
82143
  const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
82128
82144
  const json = (await res.json()) as Record<string, unknown>;