@wix/himalaya-cli 0.1572.0 → 0.1573.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.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-module.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/checkout/src/index.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-contract.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/one-app-page.d.ts +61 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/social-feed/src/index.d.ts +34 -9
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/checkout.mjs +28 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +573 -73
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-social-feed.mjs +24 -1
- package/dist/cli.mjs +123 -43
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/one-app-to-himi-app.md +54 -0
- package/guides/sdk-reference.json +28 -4
- package/guides/webview-page-sdk.md +68 -3
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/beauty-salon/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +5 -2
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +5 -2
- package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +5 -2
- package/templates/branded-lite/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/branded-lite/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +5 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +5 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +5 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +5 -2
- package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/community-club/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/community-club/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/community-club/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/events-meetups/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/events-meetups/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/gym-fitness/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/gym-fitness/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +5 -2
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +5 -2
- package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +5 -2
- package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/nonprofit-cause/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/nonprofit-cause/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +5 -2
- package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/podcast-creator/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/podcast-creator/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +5 -2
- package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/portfolio-creative/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/portfolio-creative/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +5 -2
- package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/restaurant/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/restaurant/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/restaurant/tier5-src/himi-events-detail/index.ts +9 -4
- package/templates/retail-store/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/retail-store/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +5 -2
- package/templates/yoga-studio/tier5-src/_shared/iap-worker.ts +2 -0
- package/templates/yoga-studio/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +5 -2
- package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +5 -2
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +5 -2
- package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +9 -4
|
Binary file
|
|
@@ -501,6 +501,53 @@ mapping rows are research leads: inspect the current CLI's component, SDK and
|
|
|
501
501
|
template contracts before using them. A previously empty row does not prove the
|
|
502
502
|
feature is impossible today.
|
|
503
503
|
|
|
504
|
+
### Standalone launch tab
|
|
505
|
+
|
|
506
|
+
When the reconstructed navigation has a tab bar, preserve the app's actual tab
|
|
507
|
+
IDs, source order, labels, icons and content. Do not keep the starter template's
|
|
508
|
+
`home` ID or rename the first tab to `home` merely to match a shell default.
|
|
509
|
+
An actual source tab named `home` is valid; the name is not reserved or required.
|
|
510
|
+
A tab ID is not a `screenId`: a Community tab can use `id: "community"` with
|
|
511
|
+
`screenId: "community_home"` and its visible Community label.
|
|
512
|
+
For navigation with no tab bar, do not add a synthetic Home tab.
|
|
513
|
+
|
|
514
|
+
Validate that tab IDs are non-empty and unique. Keep the source-to-target lookup,
|
|
515
|
+
every `tabId` in
|
|
516
|
+
`navigation.linkableScreens`, tab-selection actions and worker navigation requests
|
|
517
|
+
consistent with the actual destination IDs, including detail screens that belong
|
|
518
|
+
to the first tab. Remove stale template references instead of renaming the app's
|
|
519
|
+
tabs to make them match. `himi validate --strict` rejects empty or duplicate tab
|
|
520
|
+
IDs and linkable `tabId` references outside the selectable primary navigation
|
|
521
|
+
on enabled surfaces when chrome lists are configured. An auxiliary drawer row is
|
|
522
|
+
not a compact responsive tab: use an empty/default-stack `tabId` for a pushed
|
|
523
|
+
screen without an owning tab. Explicit primary drawer/sidebar modes and declared
|
|
524
|
+
surface overrides use their own destinations. This config-only membership check
|
|
525
|
+
does not prove source fidelity, dynamic navigation requests, or deep-link behavior
|
|
526
|
+
on every surface; verify those independently. For example,
|
|
527
|
+
the navigation fragment for a Community-first app is:
|
|
528
|
+
|
|
529
|
+
```json
|
|
530
|
+
{
|
|
531
|
+
"tabBar": {
|
|
532
|
+
"items": [
|
|
533
|
+
{ "id": "community", "screenId": "community_home", "label": "Community", "icon": "people" },
|
|
534
|
+
{ "id": "profile", "screenId": "member_profile", "label": "Profile", "icon": "person" }
|
|
535
|
+
]
|
|
536
|
+
},
|
|
537
|
+
"linkableScreens": [
|
|
538
|
+
{ "screenId": "community_home", "isPublic": true, "paramKeys": [], "parentScreenId": "", "tabId": "community" },
|
|
539
|
+
{ "screenId": "community_post", "isPublic": true, "paramKeys": ["id"], "parentScreenId": "community_home", "tabId": "community" }
|
|
540
|
+
]
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
Current standalone bottom-tab chrome selects the first visible configured tab
|
|
545
|
+
when its stored selection is unknown. Do not infer this fallback for sidebar or
|
|
546
|
+
responsive-wide chrome: verify its launch selection independently. A stored
|
|
547
|
+
template default such as `home` must not override the app's navigation or leave
|
|
548
|
+
it blank. If a binary does not handle the app's actual IDs, fix or update that
|
|
549
|
+
shell and report the incompatibility; do not disguise it by renaming the first tab.
|
|
550
|
+
|
|
504
551
|
## 2. Write the reconstruction plan and resolve gaps
|
|
505
552
|
|
|
506
553
|
Write `.himi/one-app/reconstruction-plan.md` before scaffolding. Describe the app
|
|
@@ -931,6 +978,13 @@ transactions against fixtures only. Read-only live checks verify the correct sit
|
|
|
931
978
|
entity selection and runtime identity; they do not authorize placing orders,
|
|
932
979
|
bookings, payments, form submissions or destructive updates during validation.
|
|
933
980
|
|
|
981
|
+
For a tabbed migration, cold-launch the standalone app without a launch-screen
|
|
982
|
+
override or incoming deep link. Confirm the first tab is selected and displays
|
|
983
|
+
content. Then switch tabs and open a detail link belonging to the first tab;
|
|
984
|
+
confirm it selects that tab and opens the intended screen. A hosted preview alone
|
|
985
|
+
does not establish standalone launch behavior. Record an unavailable native check
|
|
986
|
+
as unverified in the migration report.
|
|
987
|
+
|
|
934
988
|
The UX audit requires app-specific network fixtures. `himi test --record` records
|
|
935
989
|
only boot-time reads with the app's visitor identity, then crawls hermetically.
|
|
936
990
|
Review its recorded/refused requests; do not run a source getter known to mutate
|
|
@@ -2771,7 +2771,7 @@
|
|
|
2771
2771
|
"name": "OrderFailureCode",
|
|
2772
2772
|
"kind": "type",
|
|
2773
2773
|
"jsdoc": "",
|
|
2774
|
-
"decl": "export type OrderFailureCode =\n | \"notEnabled\" | \"notConfigured\" | \"signInRequired\" | \"unsupportedItem\" | \"notAppleRoute\"\n | \"storageUnavailable\" | \"approvalRequired\" | \"orderClosed\" | \"orderRefused\" | \"chargeFailed\"\n | \"paymentRefused\" | \"paymentHeld\" | \"alreadyOwned\" | \"paymentInProgress\" | \"productChanged\"\n | \"invalidAssociation\" | \"needsSupport\" | \"unavailable\" | \"sessionChanged\" | \"outcomeUnknown\";"
|
|
2774
|
+
"decl": "export type OrderFailureCode =\n | \"notEnabled\" | \"notConfigured\" | \"signInRequired\" | \"unsupportedItem\" | \"notAppleRoute\"\n | \"storageUnavailable\" | \"approvalRequired\" | \"orderClosed\" | \"orderRefused\" | \"chargeFailed\"\n | \"paymentRefused\" | \"paymentHeld\" | \"alreadyOwned\" | \"paymentInProgress\" | \"productChanged\"\n | \"sitePaymentUnavailable\" | \"invalidAssociation\" | \"needsSupport\" | \"unavailable\" | \"sessionChanged\" | \"outcomeUnknown\";"
|
|
2775
2775
|
},
|
|
2776
2776
|
{
|
|
2777
2777
|
"name": "PaymentAccess",
|
|
@@ -2849,7 +2849,7 @@
|
|
|
2849
2849
|
"name": "IapPurchaseCopy",
|
|
2850
2850
|
"kind": "interface",
|
|
2851
2851
|
"jsdoc": "/** Labels from the screen's copy pack; the shared layer only chooses between them. */",
|
|
2852
|
-
"decl": "export interface IapPurchaseCopy {\n buy: string;\n buyAnother?: string;\n processing: string;\n awaitingApproval: string;\n unavailable: string;\n signInRequired: string;\n retry: string;\n priceChanged: string;\n support: string;\n}"
|
|
2852
|
+
"decl": "export interface IapPurchaseCopy {\n buy: string;\n buyAnother?: string;\n processing: string;\n awaitingApproval: string;\n unavailable: string;\n signInRequired: string;\n retry: string;\n /** Optional for existing SDK consumers; the app supplies a localized recovery message. */\n sitePaymentUnavailable?: string;\n priceChanged: string;\n support: string;\n}"
|
|
2853
2853
|
},
|
|
2854
2854
|
{
|
|
2855
2855
|
"name": "IapPurchaseFields",
|
|
@@ -25560,13 +25560,37 @@
|
|
|
25560
25560
|
"jsdoc": "",
|
|
25561
25561
|
"decl": "export interface WixListFeedItemsResponse {\n feedItems: WixFeedItem[];\n profiles?: WixFeedProfile[];\n nextPageCursor?: string;\n}"
|
|
25562
25562
|
},
|
|
25563
|
+
{
|
|
25564
|
+
"name": "WixFeedPageOptions",
|
|
25565
|
+
"kind": "interface",
|
|
25566
|
+
"jsdoc": "/** Read controls shared by the source's single-group and central feeds. */",
|
|
25567
|
+
"decl": "export interface WixFeedPageOptions extends WixCallOptions {\n /** Opaque server cursor; pass it back unchanged when loading the next page. */\n cursor?: string;\n invalidatePermissionsCache?: boolean;\n}"
|
|
25568
|
+
},
|
|
25569
|
+
{
|
|
25570
|
+
"name": "WixGroupFeedOptions",
|
|
25571
|
+
"kind": "interface",
|
|
25572
|
+
"jsdoc": "",
|
|
25573
|
+
"decl": "export interface WixGroupFeedOptions extends WixFeedPageOptions {\n topicId?: string;\n}"
|
|
25574
|
+
},
|
|
25575
|
+
{
|
|
25576
|
+
"name": "WixCentralFeedOptions",
|
|
25577
|
+
"kind": "interface",
|
|
25578
|
+
"jsdoc": "",
|
|
25579
|
+
"decl": "export interface WixCentralFeedOptions extends WixFeedPageOptions {\n withSuggestedPosts?: boolean;\n /** Omit to use the central-feed service's default representation. */\n contentType?: \"DRAFTJS\";\n}"
|
|
25580
|
+
},
|
|
25563
25581
|
{
|
|
25564
25582
|
"name": "listFeedItems",
|
|
25565
25583
|
"kind": "function",
|
|
25566
|
-
"jsdoc": "/**\n * List
|
|
25567
|
-
"decl": "export function listFeedItems(groupId: string, limit = 20, options?:
|
|
25584
|
+
"jsdoc": "/**\n * List one group's activity feed. Mirrors wix-one-app-feed getFeedPosts:\n * containerId + Groups appDefId + feedType=all + contentType=DRAFTJS, with optional\n * topic and opaque paging cursor. Existing site/cache options remain per-call.\n * Reactions lists must not be treated as authoritative totals.\n *\n * @scope member — verified live with a signed-in member session; visitor readability\n * depends on group permissions and is not established by the central-feed probe.\n */",
|
|
25585
|
+
"decl": "export function listFeedItems(groupId: string, limit = 20, options?: WixGroupFeedOptions): Promise<WixListFeedItemsResponse>;",
|
|
25568
25586
|
"scope": "member"
|
|
25569
25587
|
},
|
|
25588
|
+
{
|
|
25589
|
+
"name": "listCentralFeedItems",
|
|
25590
|
+
"kind": "function",
|
|
25591
|
+
"jsdoc": "/**\n * List the site's combined feed, rather than substituting a selected group's feed.\n * Mirrors wix-one-app-feed getCentralFeedPosts: there is no containerId or appDefId.\n * Authentication and business selection belong to the bridge (or per-call `site`).\n *\n * Source: wix-one-app-feed@6ef53170e94e27349d2a6c1cf08038b078d86228,\n * src/services/feed-api.ts. A real Visitor read returned 200 with posts and a cursor.\n * That establishes the server contract only: native consumers need a core release with the exact read-route guard, and\n * production web still refuses social.wix.com. This SDK method does\n * not change those policies or establish membership/write permission. Consumers must\n * surface a transport refusal; they must not substitute a group directory or empty feed.\n */",
|
|
25592
|
+
"decl": "export function listCentralFeedItems(limit = 20, options?: WixCentralFeedOptions): Promise<WixListFeedItemsResponse>;"
|
|
25593
|
+
},
|
|
25570
25594
|
{
|
|
25571
25595
|
"name": "createFeedItem",
|
|
25572
25596
|
"kind": "function",
|
|
@@ -94,7 +94,28 @@ every message none of them claims, including a handler registered directly on
|
|
|
94
94
|
`himalaya.webview.onPageMessage` after `@himalaya/webview` loaded).
|
|
95
95
|
|
|
96
96
|
```ts
|
|
97
|
-
import {
|
|
97
|
+
import { defineService } from "@himalaya/state";
|
|
98
|
+
import { emitToPage, onPageLifecycle, onPageRequest, openPageStream, type PageStream } from "@himalaya/webview";
|
|
99
|
+
|
|
100
|
+
// The worker has NO setTimeout / setInterval on any renderer. A stream that produces over time
|
|
101
|
+
// is paced by the host clock: an action returns a `_poll`, and each tick sends the next chunk.
|
|
102
|
+
const watching = new Set<PageStream>();
|
|
103
|
+
let armed = false; // re-arming a live id with `immediate` fires an extra tick at once — arm once
|
|
104
|
+
const steps = defineService("steps", {
|
|
105
|
+
state: {},
|
|
106
|
+
actions: {
|
|
107
|
+
arm: (s) => ({ ...s, _poll: { id: "steps", intervalMs: 1000, action: "steps.tick", immediate: true } }),
|
|
108
|
+
tick: (s) => {
|
|
109
|
+
for (const stream of watching) {
|
|
110
|
+
if (stream.closed) watching.delete(stream); // ended, or the page broke out of its loop
|
|
111
|
+
else stream.next({ steps: Math.random() });
|
|
112
|
+
}
|
|
113
|
+
if (watching.size) return s;
|
|
114
|
+
armed = false;
|
|
115
|
+
return { ...s, _poll: { id: "steps", stop: true } };
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
98
119
|
|
|
99
120
|
onPageRequest("nano", {
|
|
100
121
|
// (args, ctx) → value | promise. ctx = { instanceId, requestId, active }.
|
|
@@ -102,8 +123,8 @@ onPageRequest("nano", {
|
|
|
102
123
|
// Return a stream handle to answer with many chunks.
|
|
103
124
|
"steps.watch": (_args, ctx) => {
|
|
104
125
|
const stream = openPageStream(ctx.instanceId, ctx.requestId);
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
watching.add(stream);
|
|
127
|
+
if (!armed) { armed = true; void steps.arm(); }
|
|
107
128
|
return stream;
|
|
108
129
|
},
|
|
109
130
|
});
|
|
@@ -112,6 +133,9 @@ emitToPage("*", "nano.theme.changed", { dark: true }); // or one instance id
|
|
|
112
133
|
const off = onPageLifecycle(({ instanceId, state }) => console.log(instanceId, state)); // mounted … unmounted
|
|
113
134
|
```
|
|
114
135
|
|
|
136
|
+
A timer in a worker is not a style choice: `setInterval` here throws `Can't find variable` on the
|
|
137
|
+
device, and the page sees the request fail (`_poll`: [Tier-5 guide](tier-5-add-a-screen.md#refresh-on-a-cadence-with-_poll-the-worker-has-no-clock)).
|
|
138
|
+
|
|
115
139
|
- `ctx.instanceId` is the WebView the **host** says the request came from; a page-sent `iid` is
|
|
116
140
|
ignored. `ctx.active` is live: `false` between `inactive` and `active` lifecycle events.
|
|
117
141
|
- A namespace — and an exposed capability id — follows the capability-id pattern
|
|
@@ -255,3 +279,44 @@ The page is served at `/web/webview-sdk.html`. Its companion worker is
|
|
|
255
279
|
probes. Safe probes run on load.
|
|
256
280
|
Verbs that prompt, write, or open system UI stay allowlisted and are not called. Streaming
|
|
257
281
|
helpers that return a live object stay on the worker.
|
|
282
|
+
|
|
283
|
+
## Embedding worker-bridged WebViews
|
|
284
|
+
|
|
285
|
+
A Tier-5 SDUI screen embeds any number of `WebView` nodes that talk to the **owning screen's
|
|
286
|
+
worker** over the same channel: set `bridge: "worker"` on the node, declare `"webview"`
|
|
287
|
+
in the screen's `logic_bundle`, and give each widget an explicit `instance_id` (inside a
|
|
288
|
+
`LazyList`/`Carousel` item template it must be item-derived, e.g. `"row-$item.id"`). Untrusted or
|
|
289
|
+
LLM-generated inline HTML additionally wants `origin_isolation: "per_instance"` (its own origin +
|
|
290
|
+
storage per widget), `frame_policy: "content"` (top frame pinned, bridge main-frame-only),
|
|
291
|
+
`bridge_security: { profile: "app_content" }` (multi-line-friendly caps) and `console_forwarding`.
|
|
292
|
+
The host injects the page client at document start, so the page imports nothing; an app alias
|
|
293
|
+
(`inject_js_document_start: "window.demoSdk = himalaya.demo;"`) runs after it, and the platform
|
|
294
|
+
knows no app names. On web (phase 1), only an app-controlled **cross-origin `url`** page listed in
|
|
295
|
+
`allowed_origins` is bridged; an inline (`srcdoc`) widget stays unbridged and the worker hears
|
|
296
|
+
`mounted` with `detail: { bridged: false, reason: "web_srcdoc_unbridged" }` — show a fallback.
|
|
297
|
+
|
|
298
|
+
A complete shape to copy — the demo app's **Embedded widgets** screen (`demo_app_embedded_widgets`)
|
|
299
|
+
is built exactly this way:
|
|
300
|
+
|
|
301
|
+
- three isolated inline widgets in a `Carousel` with `live_window: 1`, so only the current widget
|
|
302
|
+
and its neighbours are mounted (swiping to widget 3 unmounts widget 1), plus one bridged
|
|
303
|
+
cross-origin `url` page — all served by **one** worker;
|
|
304
|
+
- the worker answers `onPageRequest("demo", { echo, bump, stream })`: a request, a per-instance
|
|
305
|
+
counter that answers with `emitToPage(ctx.instanceId, "demo.tick", n)`, and a 5-chunk stream the
|
|
306
|
+
page can stop (`break` out of its loop), paced by a host `_poll` as above;
|
|
307
|
+
- `muted_path`, `active_path` and one widget's `reload_key_path` bound to worker state, and an
|
|
308
|
+
`onPageLifecycle` handler that shows each widget's last state;
|
|
309
|
+
- each widget keeps its own `localStorage` counter, which survives a relaunch and is never visible
|
|
310
|
+
to its neighbours.
|
|
311
|
+
|
|
312
|
+
Test such a screen by the document, not only by lifecycle envelopes: put state in a widget's page
|
|
313
|
+
(an echo reply), swipe away and back, and check the state survived where the widget should have
|
|
314
|
+
stayed mounted. **Crash recovery:** when a widget's content process dies, the host sends `crashed`
|
|
315
|
+
and then remounts it (`reloaded`). On iOS and macOS each widget has its own content process, so the
|
|
316
|
+
page exhausting memory (the demo's "Crash widget 3" does) kills only that widget; killing the
|
|
317
|
+
`com.apple.WebKit.WebContent` process serving it by hand on a simulator triggers the same two
|
|
318
|
+
envelopes. **On Android, don't use a memory hog:** one renderer process serves every WebView of the
|
|
319
|
+
app — the screen's own worker included — so the hog takes them all down, and repeated renderer
|
|
320
|
+
crashes exhaust the worker's recovery budget. Trigger it by hand instead: kill the app's sandboxed
|
|
321
|
+
WebView process (`adb shell ps -A | grep sandboxed_process`, then `adb shell kill <pid>`) and watch
|
|
322
|
+
for `crashed` then `reloaded`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1573.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "39a44e1a057f7d34899d550863397025bfdec7b4f241a6e45b677246"
|
|
75
75
|
}
|
|
@@ -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 { 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
|
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
|
-
|
|
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
|
}
|
|
@@ -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 { 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
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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!);
|
|
@@ -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 {
|
|
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!);
|
|
@@ -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."),
|