@wix/himalaya-cli 0.1345.0 → 0.1348.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/sdk/presigned-upload/src/index.d.ts +5 -12
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/checkout/src/index.d.ts +7 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/checkout.mjs +7 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +7 -2
- package/dist/cli.mjs +102 -47
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/sdk-reference.json +1 -1
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/_shared/hosted-checkout.ts +42 -0
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +9 -3
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +11 -3
- package/templates/branded-lite/tier5-src/_shared/hosted-checkout.ts +42 -0
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +9 -3
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +11 -3
- package/templates/gym-fitness/tier5-src/_shared/hosted-checkout.ts +42 -0
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +9 -3
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +11 -3
- package/templates/portfolio-creative/tier5-src/_shared/hosted-checkout.ts +42 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +11 -3
- package/templates/retail-store/tier5-src/_shared/hosted-checkout.ts +42 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +11 -3
- package/templates/yoga-studio/tier5-src/_shared/hosted-checkout.ts +42 -0
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +9 -3
|
Binary file
|
|
@@ -3543,7 +3543,7 @@
|
|
|
3543
3543
|
{
|
|
3544
3544
|
"name": "putFile",
|
|
3545
3545
|
"kind": "function",
|
|
3546
|
-
"jsdoc": "/**\n * Upload a stored file's bytes to a pre-signed URL, read straight from the\n * `@himalaya/files` substrate — the bytes never cross the worker bridge, so this is\n * the path for photos and voice notes.\n *\n * DECLARE \"files\" TOO. This verb reads the app's document substrate, so
|
|
3546
|
+
"jsdoc": "/**\n * Upload a stored file's bytes to a pre-signed URL, read straight from the\n * `@himalaya/files` substrate — the bytes never cross the worker bridge, so this is\n * the path for photos and voice notes.\n *\n * DECLARE \"files\" TOO — it is REQUIRED. This verb reads the app's document substrate, so\n * the worker gate on every runtime (iOS, macOS, Android, web) refuses\n * `capability.presigned_upload.putFile` to a bundle that does not also declare `files`.\n * Deliberately a requirement and NOT a `presigned_upload → files` implication:\n * declaring `presigned_upload` grants none of the files surface (write, remove, list).\n */",
|
|
3547
3547
|
"decl": "export async function putFile(\n url: string,\n ref: FileHandle | string,\n opts?: UploadOptions,\n): Promise<UploadResult>;"
|
|
3548
3548
|
},
|
|
3549
3549
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1348.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": "ff7251a5688611526e72aaae9882c46d2f4f3667bbd4f0fa94b5343f"
|
|
75
75
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hosted checkout (#4089 B3). A Branded Lite hosted in a host shell (Spaces)
|
|
2
|
+
// pays as the member the host lent it: Headless `createRedirectSession` does not take a Member
|
|
3
|
+
// instance, so the HOST opens the site's checkout signed in as that member. The worker names only
|
|
4
|
+
// its ecom checkout; the host reads Wix's checkout URL, mints a one-time member session and opens
|
|
5
|
+
// the site's `createSessionCookie` → checkout. The session token never reaches this worker.
|
|
6
|
+
|
|
7
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
8
|
+
import { hostSiteFromInput } from "./branded-lite-hosted.js";
|
|
9
|
+
|
|
10
|
+
/** The host verbs (registered by the host shell, never by the app itself). The first prepares the
|
|
11
|
+
* checkout and answers a one-time ticket; the second opens it. Two steps so the caller's charge guard
|
|
12
|
+
* is re-read after the host's network round trips and right before the checkout opens — the prepared
|
|
13
|
+
* URL (which carries the member's session token) stays in the host; only the ticket crosses here. */
|
|
14
|
+
export const HOSTED_CHECKOUT_ACTION = "himi.host.memberCheckout";
|
|
15
|
+
export const HOSTED_CHECKOUT_OPEN_ACTION = "himi.host.memberCheckout.open";
|
|
16
|
+
|
|
17
|
+
/** Whether this worker runs inside a host that opened a site for it. */
|
|
18
|
+
export function isHostedWorker(): boolean {
|
|
19
|
+
return hostSiteFromInput((globalThis as { himalaya?: { input?: unknown } }).himalaya?.input) !== null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type HostAnswer = { opened?: unknown; ticket?: unknown; payload?: { opened?: unknown; ticket?: unknown } } | null;
|
|
23
|
+
|
|
24
|
+
/** `payCashierOrder`'s `openCashier` for a hosted app: the host prepares [checkoutId]'s checkout as the
|
|
25
|
+
* lent member, the caller's guard is re-read, and only then does the host open it. Resolves whether it
|
|
26
|
+
* opened ("withdrawn" when the guard said no); a host without the verbs (or that refused) → false. */
|
|
27
|
+
export function hostedCheckoutOpener(checkoutId: string): (stillMayCharge: () => Promise<boolean>) => Promise<boolean | "withdrawn"> {
|
|
28
|
+
return async (stillMayCharge) => {
|
|
29
|
+
try {
|
|
30
|
+
const prepared = await dispatch(HOSTED_CHECKOUT_ACTION, { checkoutId }) as HostAnswer;
|
|
31
|
+
const ticket = prepared?.ticket ?? prepared?.payload?.ticket;
|
|
32
|
+
if (typeof ticket !== "string" || !ticket) return false;
|
|
33
|
+
// An unopened ticket simply expires in the host: nothing to cancel.
|
|
34
|
+
if (!(await stillMayCharge())) return "withdrawn";
|
|
35
|
+
const result = await dispatch(HOSTED_CHECKOUT_OPEN_ACTION, { ticket }) as HostAnswer;
|
|
36
|
+
const opened = result?.opened ?? result?.payload?.opened;
|
|
37
|
+
return opened === true || opened === "true";
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -9,6 +9,7 @@ import { bookSlot, getService, queryServiceAvailability, type WixBookingSlotFull
|
|
|
9
9
|
import { createCheckout, createOrder } from "@himalaya/wix-ecom";
|
|
10
10
|
import { createRedirectSession, type WixSlot } from "@himalaya/wix-redirects";
|
|
11
11
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
12
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
12
13
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
13
14
|
import { displayName, getMyData, type WixMyData } from "@himalaya/wix-users";
|
|
14
15
|
import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-price.js";
|
|
@@ -662,9 +663,12 @@ const svc = defineService<S, {
|
|
|
662
663
|
// 3. Create the Wix-managed order — mints the cashier snapshot when a
|
|
663
664
|
// balance is due. No paymentGatewayOrderId ⇒ nothing to charge
|
|
664
665
|
// (covered / zero total) ⇒ the booking is already confirmed.
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
666
|
+
// Hosted (Spaces): the site's own checkout page creates the order (as
|
|
667
|
+
// RN does) — creating it here first fails on a site with no payment method set up.
|
|
668
|
+
const hosted = isHostedWorker();
|
|
669
|
+
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
|
+
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
|
+
if (!snapshotId && !hosted) {
|
|
668
672
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
669
673
|
}
|
|
670
674
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -676,6 +680,8 @@ const svc = defineService<S, {
|
|
|
676
680
|
appId: WIX_BOOKINGS_APP_ID,
|
|
677
681
|
snapshotId,
|
|
678
682
|
msid: await resolveMsid(),
|
|
683
|
+
// Hosted (Spaces): the host opens this booking's checkout as the lent member.
|
|
684
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
679
685
|
cashierUrl: async () => {
|
|
680
686
|
const redirect = await createRedirectSession({
|
|
681
687
|
bookingsCheckout: { slotAvailability: { slot: slot as unknown as WixSlot } },
|
|
@@ -6,6 +6,7 @@ import { createCheckoutFromCurrentCart, createOrder, getCurrentCart, removeLineI
|
|
|
6
6
|
import { createRedirectSession } from "@himalaya/wix-redirects";
|
|
7
7
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
8
8
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
9
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
9
10
|
|
|
10
11
|
/** Wix Stores appDefId — the vertical that owns a cart/ecom order, and therefore the
|
|
11
12
|
* `appId` its cashier order is paid under. (Same constant Wix's own tooling uses.) */
|
|
@@ -317,9 +318,13 @@ const svc = defineService<State, {
|
|
|
317
318
|
if (!checkout.checkoutId) return derive({ ...state, checkoutHint: copyParam("cart.checkoutIdMissingMessage", "Wix did not return a checkout id.") });
|
|
318
319
|
const checkoutId = checkout.checkoutId;
|
|
319
320
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// Hosted (Spaces): the site's own checkout page creates the order (RN's
|
|
322
|
+
// route) — creating it here first fails on a site with no payment method set up, before the
|
|
323
|
+
// member ever reaches the checkout. The host opens the checkout as the lent member.
|
|
324
|
+
const hosted = isHostedWorker();
|
|
325
|
+
const order = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
326
|
+
const snapshotId = order.paymentGatewayOrderId ?? "";
|
|
327
|
+
if (!snapshotId && !hosted) {
|
|
323
328
|
return derive({ ...state, ...cartConsumedByOrder() });
|
|
324
329
|
}
|
|
325
330
|
|
|
@@ -335,6 +340,9 @@ const svc = defineService<State, {
|
|
|
335
340
|
return !!reference && cartPricing.pricing.continueCheckoutGuard({ kind: "storesProduct", id: reference.catalogItemId }).allowed;
|
|
336
341
|
});
|
|
337
342
|
},
|
|
343
|
+
// Hosted (Spaces): the host opens the checkout as the lent member — Headless redirect
|
|
344
|
+
// sessions do not take a Member instance.
|
|
345
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
338
346
|
cashierUrl: async () => {
|
|
339
347
|
const redirect = await createRedirectSession({
|
|
340
348
|
ecomCheckout: { checkoutId },
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hosted checkout (#4089 B3). A Branded Lite hosted in a host shell (Spaces)
|
|
2
|
+
// pays as the member the host lent it: Headless `createRedirectSession` does not take a Member
|
|
3
|
+
// instance, so the HOST opens the site's checkout signed in as that member. The worker names only
|
|
4
|
+
// its ecom checkout; the host reads Wix's checkout URL, mints a one-time member session and opens
|
|
5
|
+
// the site's `createSessionCookie` → checkout. The session token never reaches this worker.
|
|
6
|
+
|
|
7
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
8
|
+
import { hostSiteFromInput } from "./branded-lite-hosted.js";
|
|
9
|
+
|
|
10
|
+
/** The host verbs (registered by the host shell, never by the app itself). The first prepares the
|
|
11
|
+
* checkout and answers a one-time ticket; the second opens it. Two steps so the caller's charge guard
|
|
12
|
+
* is re-read after the host's network round trips and right before the checkout opens — the prepared
|
|
13
|
+
* URL (which carries the member's session token) stays in the host; only the ticket crosses here. */
|
|
14
|
+
export const HOSTED_CHECKOUT_ACTION = "himi.host.memberCheckout";
|
|
15
|
+
export const HOSTED_CHECKOUT_OPEN_ACTION = "himi.host.memberCheckout.open";
|
|
16
|
+
|
|
17
|
+
/** Whether this worker runs inside a host that opened a site for it. */
|
|
18
|
+
export function isHostedWorker(): boolean {
|
|
19
|
+
return hostSiteFromInput((globalThis as { himalaya?: { input?: unknown } }).himalaya?.input) !== null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type HostAnswer = { opened?: unknown; ticket?: unknown; payload?: { opened?: unknown; ticket?: unknown } } | null;
|
|
23
|
+
|
|
24
|
+
/** `payCashierOrder`'s `openCashier` for a hosted app: the host prepares [checkoutId]'s checkout as the
|
|
25
|
+
* lent member, the caller's guard is re-read, and only then does the host open it. Resolves whether it
|
|
26
|
+
* opened ("withdrawn" when the guard said no); a host without the verbs (or that refused) → false. */
|
|
27
|
+
export function hostedCheckoutOpener(checkoutId: string): (stillMayCharge: () => Promise<boolean>) => Promise<boolean | "withdrawn"> {
|
|
28
|
+
return async (stillMayCharge) => {
|
|
29
|
+
try {
|
|
30
|
+
const prepared = await dispatch(HOSTED_CHECKOUT_ACTION, { checkoutId }) as HostAnswer;
|
|
31
|
+
const ticket = prepared?.ticket ?? prepared?.payload?.ticket;
|
|
32
|
+
if (typeof ticket !== "string" || !ticket) return false;
|
|
33
|
+
// An unopened ticket simply expires in the host: nothing to cancel.
|
|
34
|
+
if (!(await stillMayCharge())) return "withdrawn";
|
|
35
|
+
const result = await dispatch(HOSTED_CHECKOUT_OPEN_ACTION, { ticket }) as HostAnswer;
|
|
36
|
+
const opened = result?.opened ?? result?.payload?.opened;
|
|
37
|
+
return opened === true || opened === "true";
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -9,6 +9,7 @@ import { bookSlot, getService, queryServiceAvailability, type WixBookingSlotFull
|
|
|
9
9
|
import { createCheckout, createOrder } from "@himalaya/wix-ecom";
|
|
10
10
|
import { createRedirectSession, type WixSlot } from "@himalaya/wix-redirects";
|
|
11
11
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
12
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
12
13
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
13
14
|
import { displayName, getMyData, type WixMyData } from "@himalaya/wix-users";
|
|
14
15
|
import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-price.js";
|
|
@@ -662,9 +663,12 @@ const svc = defineService<S, {
|
|
|
662
663
|
// 3. Create the Wix-managed order — mints the cashier snapshot when a
|
|
663
664
|
// balance is due. No paymentGatewayOrderId ⇒ nothing to charge
|
|
664
665
|
// (covered / zero total) ⇒ the booking is already confirmed.
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
666
|
+
// Hosted (Spaces): the site's own checkout page creates the order (as
|
|
667
|
+
// RN does) — creating it here first fails on a site with no payment method set up.
|
|
668
|
+
const hosted = isHostedWorker();
|
|
669
|
+
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
|
+
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
|
+
if (!snapshotId && !hosted) {
|
|
668
672
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
669
673
|
}
|
|
670
674
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -676,6 +680,8 @@ const svc = defineService<S, {
|
|
|
676
680
|
appId: WIX_BOOKINGS_APP_ID,
|
|
677
681
|
snapshotId,
|
|
678
682
|
msid: await resolveMsid(),
|
|
683
|
+
// Hosted (Spaces): the host opens this booking's checkout as the lent member.
|
|
684
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
679
685
|
cashierUrl: async () => {
|
|
680
686
|
const redirect = await createRedirectSession({
|
|
681
687
|
bookingsCheckout: { slotAvailability: { slot: slot as unknown as WixSlot } },
|
|
@@ -6,6 +6,7 @@ import { createCheckoutFromCurrentCart, createOrder, getCurrentCart, removeLineI
|
|
|
6
6
|
import { createRedirectSession } from "@himalaya/wix-redirects";
|
|
7
7
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
8
8
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
9
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
9
10
|
|
|
10
11
|
/** Wix Stores appDefId — the vertical that owns a cart/ecom order, and therefore the
|
|
11
12
|
* `appId` its cashier order is paid under. (Same constant Wix's own tooling uses.) */
|
|
@@ -317,9 +318,13 @@ const svc = defineService<State, {
|
|
|
317
318
|
if (!checkout.checkoutId) return derive({ ...state, checkoutHint: copyParam("cart.checkoutIdMissingMessage", "Wix did not return a checkout id.") });
|
|
318
319
|
const checkoutId = checkout.checkoutId;
|
|
319
320
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// Hosted (Spaces): the site's own checkout page creates the order (RN's
|
|
322
|
+
// route) — creating it here first fails on a site with no payment method set up, before the
|
|
323
|
+
// member ever reaches the checkout. The host opens the checkout as the lent member.
|
|
324
|
+
const hosted = isHostedWorker();
|
|
325
|
+
const order = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
326
|
+
const snapshotId = order.paymentGatewayOrderId ?? "";
|
|
327
|
+
if (!snapshotId && !hosted) {
|
|
323
328
|
return derive({ ...state, ...cartConsumedByOrder() });
|
|
324
329
|
}
|
|
325
330
|
|
|
@@ -335,6 +340,9 @@ const svc = defineService<State, {
|
|
|
335
340
|
return !!reference && cartPricing.pricing.continueCheckoutGuard({ kind: "storesProduct", id: reference.catalogItemId }).allowed;
|
|
336
341
|
});
|
|
337
342
|
},
|
|
343
|
+
// Hosted (Spaces): the host opens the checkout as the lent member — Headless redirect
|
|
344
|
+
// sessions do not take a Member instance.
|
|
345
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
338
346
|
cashierUrl: async () => {
|
|
339
347
|
const redirect = await createRedirectSession({
|
|
340
348
|
ecomCheckout: { checkoutId },
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hosted checkout (#4089 B3). A Branded Lite hosted in a host shell (Spaces)
|
|
2
|
+
// pays as the member the host lent it: Headless `createRedirectSession` does not take a Member
|
|
3
|
+
// instance, so the HOST opens the site's checkout signed in as that member. The worker names only
|
|
4
|
+
// its ecom checkout; the host reads Wix's checkout URL, mints a one-time member session and opens
|
|
5
|
+
// the site's `createSessionCookie` → checkout. The session token never reaches this worker.
|
|
6
|
+
|
|
7
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
8
|
+
import { hostSiteFromInput } from "./branded-lite-hosted.js";
|
|
9
|
+
|
|
10
|
+
/** The host verbs (registered by the host shell, never by the app itself). The first prepares the
|
|
11
|
+
* checkout and answers a one-time ticket; the second opens it. Two steps so the caller's charge guard
|
|
12
|
+
* is re-read after the host's network round trips and right before the checkout opens — the prepared
|
|
13
|
+
* URL (which carries the member's session token) stays in the host; only the ticket crosses here. */
|
|
14
|
+
export const HOSTED_CHECKOUT_ACTION = "himi.host.memberCheckout";
|
|
15
|
+
export const HOSTED_CHECKOUT_OPEN_ACTION = "himi.host.memberCheckout.open";
|
|
16
|
+
|
|
17
|
+
/** Whether this worker runs inside a host that opened a site for it. */
|
|
18
|
+
export function isHostedWorker(): boolean {
|
|
19
|
+
return hostSiteFromInput((globalThis as { himalaya?: { input?: unknown } }).himalaya?.input) !== null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type HostAnswer = { opened?: unknown; ticket?: unknown; payload?: { opened?: unknown; ticket?: unknown } } | null;
|
|
23
|
+
|
|
24
|
+
/** `payCashierOrder`'s `openCashier` for a hosted app: the host prepares [checkoutId]'s checkout as the
|
|
25
|
+
* lent member, the caller's guard is re-read, and only then does the host open it. Resolves whether it
|
|
26
|
+
* opened ("withdrawn" when the guard said no); a host without the verbs (or that refused) → false. */
|
|
27
|
+
export function hostedCheckoutOpener(checkoutId: string): (stillMayCharge: () => Promise<boolean>) => Promise<boolean | "withdrawn"> {
|
|
28
|
+
return async (stillMayCharge) => {
|
|
29
|
+
try {
|
|
30
|
+
const prepared = await dispatch(HOSTED_CHECKOUT_ACTION, { checkoutId }) as HostAnswer;
|
|
31
|
+
const ticket = prepared?.ticket ?? prepared?.payload?.ticket;
|
|
32
|
+
if (typeof ticket !== "string" || !ticket) return false;
|
|
33
|
+
// An unopened ticket simply expires in the host: nothing to cancel.
|
|
34
|
+
if (!(await stillMayCharge())) return "withdrawn";
|
|
35
|
+
const result = await dispatch(HOSTED_CHECKOUT_OPEN_ACTION, { ticket }) as HostAnswer;
|
|
36
|
+
const opened = result?.opened ?? result?.payload?.opened;
|
|
37
|
+
return opened === true || opened === "true";
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -9,6 +9,7 @@ import { bookSlot, getService, queryServiceAvailability, type WixBookingSlotFull
|
|
|
9
9
|
import { createCheckout, createOrder } from "@himalaya/wix-ecom";
|
|
10
10
|
import { createRedirectSession, type WixSlot } from "@himalaya/wix-redirects";
|
|
11
11
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
12
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
12
13
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
13
14
|
import { displayName, getMyData, type WixMyData } from "@himalaya/wix-users";
|
|
14
15
|
import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-price.js";
|
|
@@ -662,9 +663,12 @@ const svc = defineService<S, {
|
|
|
662
663
|
// 3. Create the Wix-managed order — mints the cashier snapshot when a
|
|
663
664
|
// balance is due. No paymentGatewayOrderId ⇒ nothing to charge
|
|
664
665
|
// (covered / zero total) ⇒ the booking is already confirmed.
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
666
|
+
// Hosted (Spaces): the site's own checkout page creates the order (as
|
|
667
|
+
// RN does) — creating it here first fails on a site with no payment method set up.
|
|
668
|
+
const hosted = isHostedWorker();
|
|
669
|
+
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
|
+
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
|
+
if (!snapshotId && !hosted) {
|
|
668
672
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
669
673
|
}
|
|
670
674
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -676,6 +680,8 @@ const svc = defineService<S, {
|
|
|
676
680
|
appId: WIX_BOOKINGS_APP_ID,
|
|
677
681
|
snapshotId,
|
|
678
682
|
msid: await resolveMsid(),
|
|
683
|
+
// Hosted (Spaces): the host opens this booking's checkout as the lent member.
|
|
684
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
679
685
|
cashierUrl: async () => {
|
|
680
686
|
const redirect = await createRedirectSession({
|
|
681
687
|
bookingsCheckout: { slotAvailability: { slot: slot as unknown as WixSlot } },
|
|
@@ -6,6 +6,7 @@ import { createCheckoutFromCurrentCart, createOrder, getCurrentCart, removeLineI
|
|
|
6
6
|
import { createRedirectSession } from "@himalaya/wix-redirects";
|
|
7
7
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
8
8
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
9
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
9
10
|
|
|
10
11
|
/** Wix Stores appDefId — the vertical that owns a cart/ecom order, and therefore the
|
|
11
12
|
* `appId` its cashier order is paid under. (Same constant Wix's own tooling uses.) */
|
|
@@ -317,9 +318,13 @@ const svc = defineService<State, {
|
|
|
317
318
|
if (!checkout.checkoutId) return derive({ ...state, checkoutHint: copyParam("cart.checkoutIdMissingMessage", "Wix did not return a checkout id.") });
|
|
318
319
|
const checkoutId = checkout.checkoutId;
|
|
319
320
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// Hosted (Spaces): the site's own checkout page creates the order (RN's
|
|
322
|
+
// route) — creating it here first fails on a site with no payment method set up, before the
|
|
323
|
+
// member ever reaches the checkout. The host opens the checkout as the lent member.
|
|
324
|
+
const hosted = isHostedWorker();
|
|
325
|
+
const order = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
326
|
+
const snapshotId = order.paymentGatewayOrderId ?? "";
|
|
327
|
+
if (!snapshotId && !hosted) {
|
|
323
328
|
return derive({ ...state, ...cartConsumedByOrder() });
|
|
324
329
|
}
|
|
325
330
|
|
|
@@ -335,6 +340,9 @@ const svc = defineService<State, {
|
|
|
335
340
|
return !!reference && cartPricing.pricing.continueCheckoutGuard({ kind: "storesProduct", id: reference.catalogItemId }).allowed;
|
|
336
341
|
});
|
|
337
342
|
},
|
|
343
|
+
// Hosted (Spaces): the host opens the checkout as the lent member — Headless redirect
|
|
344
|
+
// sessions do not take a Member instance.
|
|
345
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
338
346
|
cashierUrl: async () => {
|
|
339
347
|
const redirect = await createRedirectSession({
|
|
340
348
|
ecomCheckout: { checkoutId },
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hosted checkout (#4089 B3). A Branded Lite hosted in a host shell (Spaces)
|
|
2
|
+
// pays as the member the host lent it: Headless `createRedirectSession` does not take a Member
|
|
3
|
+
// instance, so the HOST opens the site's checkout signed in as that member. The worker names only
|
|
4
|
+
// its ecom checkout; the host reads Wix's checkout URL, mints a one-time member session and opens
|
|
5
|
+
// the site's `createSessionCookie` → checkout. The session token never reaches this worker.
|
|
6
|
+
|
|
7
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
8
|
+
import { hostSiteFromInput } from "./branded-lite-hosted.js";
|
|
9
|
+
|
|
10
|
+
/** The host verbs (registered by the host shell, never by the app itself). The first prepares the
|
|
11
|
+
* checkout and answers a one-time ticket; the second opens it. Two steps so the caller's charge guard
|
|
12
|
+
* is re-read after the host's network round trips and right before the checkout opens — the prepared
|
|
13
|
+
* URL (which carries the member's session token) stays in the host; only the ticket crosses here. */
|
|
14
|
+
export const HOSTED_CHECKOUT_ACTION = "himi.host.memberCheckout";
|
|
15
|
+
export const HOSTED_CHECKOUT_OPEN_ACTION = "himi.host.memberCheckout.open";
|
|
16
|
+
|
|
17
|
+
/** Whether this worker runs inside a host that opened a site for it. */
|
|
18
|
+
export function isHostedWorker(): boolean {
|
|
19
|
+
return hostSiteFromInput((globalThis as { himalaya?: { input?: unknown } }).himalaya?.input) !== null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type HostAnswer = { opened?: unknown; ticket?: unknown; payload?: { opened?: unknown; ticket?: unknown } } | null;
|
|
23
|
+
|
|
24
|
+
/** `payCashierOrder`'s `openCashier` for a hosted app: the host prepares [checkoutId]'s checkout as the
|
|
25
|
+
* lent member, the caller's guard is re-read, and only then does the host open it. Resolves whether it
|
|
26
|
+
* opened ("withdrawn" when the guard said no); a host without the verbs (or that refused) → false. */
|
|
27
|
+
export function hostedCheckoutOpener(checkoutId: string): (stillMayCharge: () => Promise<boolean>) => Promise<boolean | "withdrawn"> {
|
|
28
|
+
return async (stillMayCharge) => {
|
|
29
|
+
try {
|
|
30
|
+
const prepared = await dispatch(HOSTED_CHECKOUT_ACTION, { checkoutId }) as HostAnswer;
|
|
31
|
+
const ticket = prepared?.ticket ?? prepared?.payload?.ticket;
|
|
32
|
+
if (typeof ticket !== "string" || !ticket) return false;
|
|
33
|
+
// An unopened ticket simply expires in the host: nothing to cancel.
|
|
34
|
+
if (!(await stillMayCharge())) return "withdrawn";
|
|
35
|
+
const result = await dispatch(HOSTED_CHECKOUT_OPEN_ACTION, { ticket }) as HostAnswer;
|
|
36
|
+
const opened = result?.opened ?? result?.payload?.opened;
|
|
37
|
+
return opened === true || opened === "true";
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -6,6 +6,7 @@ import { createCheckoutFromCurrentCart, createOrder, getCurrentCart, removeLineI
|
|
|
6
6
|
import { createRedirectSession } from "@himalaya/wix-redirects";
|
|
7
7
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
8
8
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
9
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
9
10
|
|
|
10
11
|
/** Wix Stores appDefId — the vertical that owns a cart/ecom order, and therefore the
|
|
11
12
|
* `appId` its cashier order is paid under. (Same constant Wix's own tooling uses.) */
|
|
@@ -317,9 +318,13 @@ const svc = defineService<State, {
|
|
|
317
318
|
if (!checkout.checkoutId) return derive({ ...state, checkoutHint: copyParam("cart.checkoutIdMissingMessage", "Wix did not return a checkout id.") });
|
|
318
319
|
const checkoutId = checkout.checkoutId;
|
|
319
320
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// Hosted (Spaces): the site's own checkout page creates the order (RN's
|
|
322
|
+
// route) — creating it here first fails on a site with no payment method set up, before the
|
|
323
|
+
// member ever reaches the checkout. The host opens the checkout as the lent member.
|
|
324
|
+
const hosted = isHostedWorker();
|
|
325
|
+
const order = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
326
|
+
const snapshotId = order.paymentGatewayOrderId ?? "";
|
|
327
|
+
if (!snapshotId && !hosted) {
|
|
323
328
|
return derive({ ...state, ...cartConsumedByOrder() });
|
|
324
329
|
}
|
|
325
330
|
|
|
@@ -335,6 +340,9 @@ const svc = defineService<State, {
|
|
|
335
340
|
return !!reference && cartPricing.pricing.continueCheckoutGuard({ kind: "storesProduct", id: reference.catalogItemId }).allowed;
|
|
336
341
|
});
|
|
337
342
|
},
|
|
343
|
+
// Hosted (Spaces): the host opens the checkout as the lent member — Headless redirect
|
|
344
|
+
// sessions do not take a Member instance.
|
|
345
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
338
346
|
cashierUrl: async () => {
|
|
339
347
|
const redirect = await createRedirectSession({
|
|
340
348
|
ecomCheckout: { checkoutId },
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hosted checkout (#4089 B3). A Branded Lite hosted in a host shell (Spaces)
|
|
2
|
+
// pays as the member the host lent it: Headless `createRedirectSession` does not take a Member
|
|
3
|
+
// instance, so the HOST opens the site's checkout signed in as that member. The worker names only
|
|
4
|
+
// its ecom checkout; the host reads Wix's checkout URL, mints a one-time member session and opens
|
|
5
|
+
// the site's `createSessionCookie` → checkout. The session token never reaches this worker.
|
|
6
|
+
|
|
7
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
8
|
+
import { hostSiteFromInput } from "./branded-lite-hosted.js";
|
|
9
|
+
|
|
10
|
+
/** The host verbs (registered by the host shell, never by the app itself). The first prepares the
|
|
11
|
+
* checkout and answers a one-time ticket; the second opens it. Two steps so the caller's charge guard
|
|
12
|
+
* is re-read after the host's network round trips and right before the checkout opens — the prepared
|
|
13
|
+
* URL (which carries the member's session token) stays in the host; only the ticket crosses here. */
|
|
14
|
+
export const HOSTED_CHECKOUT_ACTION = "himi.host.memberCheckout";
|
|
15
|
+
export const HOSTED_CHECKOUT_OPEN_ACTION = "himi.host.memberCheckout.open";
|
|
16
|
+
|
|
17
|
+
/** Whether this worker runs inside a host that opened a site for it. */
|
|
18
|
+
export function isHostedWorker(): boolean {
|
|
19
|
+
return hostSiteFromInput((globalThis as { himalaya?: { input?: unknown } }).himalaya?.input) !== null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type HostAnswer = { opened?: unknown; ticket?: unknown; payload?: { opened?: unknown; ticket?: unknown } } | null;
|
|
23
|
+
|
|
24
|
+
/** `payCashierOrder`'s `openCashier` for a hosted app: the host prepares [checkoutId]'s checkout as the
|
|
25
|
+
* lent member, the caller's guard is re-read, and only then does the host open it. Resolves whether it
|
|
26
|
+
* opened ("withdrawn" when the guard said no); a host without the verbs (or that refused) → false. */
|
|
27
|
+
export function hostedCheckoutOpener(checkoutId: string): (stillMayCharge: () => Promise<boolean>) => Promise<boolean | "withdrawn"> {
|
|
28
|
+
return async (stillMayCharge) => {
|
|
29
|
+
try {
|
|
30
|
+
const prepared = await dispatch(HOSTED_CHECKOUT_ACTION, { checkoutId }) as HostAnswer;
|
|
31
|
+
const ticket = prepared?.ticket ?? prepared?.payload?.ticket;
|
|
32
|
+
if (typeof ticket !== "string" || !ticket) return false;
|
|
33
|
+
// An unopened ticket simply expires in the host: nothing to cancel.
|
|
34
|
+
if (!(await stillMayCharge())) return "withdrawn";
|
|
35
|
+
const result = await dispatch(HOSTED_CHECKOUT_OPEN_ACTION, { ticket }) as HostAnswer;
|
|
36
|
+
const opened = result?.opened ?? result?.payload?.opened;
|
|
37
|
+
return opened === true || opened === "true";
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -6,6 +6,7 @@ import { createCheckoutFromCurrentCart, createOrder, getCurrentCart, removeLineI
|
|
|
6
6
|
import { createRedirectSession } from "@himalaya/wix-redirects";
|
|
7
7
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
8
8
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
9
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
9
10
|
|
|
10
11
|
/** Wix Stores appDefId — the vertical that owns a cart/ecom order, and therefore the
|
|
11
12
|
* `appId` its cashier order is paid under. (Same constant Wix's own tooling uses.) */
|
|
@@ -317,9 +318,13 @@ const svc = defineService<State, {
|
|
|
317
318
|
if (!checkout.checkoutId) return derive({ ...state, checkoutHint: copyParam("cart.checkoutIdMissingMessage", "Wix did not return a checkout id.") });
|
|
318
319
|
const checkoutId = checkout.checkoutId;
|
|
319
320
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// Hosted (Spaces): the site's own checkout page creates the order (RN's
|
|
322
|
+
// route) — creating it here first fails on a site with no payment method set up, before the
|
|
323
|
+
// member ever reaches the checkout. The host opens the checkout as the lent member.
|
|
324
|
+
const hosted = isHostedWorker();
|
|
325
|
+
const order = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
326
|
+
const snapshotId = order.paymentGatewayOrderId ?? "";
|
|
327
|
+
if (!snapshotId && !hosted) {
|
|
323
328
|
return derive({ ...state, ...cartConsumedByOrder() });
|
|
324
329
|
}
|
|
325
330
|
|
|
@@ -335,6 +340,9 @@ const svc = defineService<State, {
|
|
|
335
340
|
return !!reference && cartPricing.pricing.continueCheckoutGuard({ kind: "storesProduct", id: reference.catalogItemId }).allowed;
|
|
336
341
|
});
|
|
337
342
|
},
|
|
343
|
+
// Hosted (Spaces): the host opens the checkout as the lent member — Headless redirect
|
|
344
|
+
// sessions do not take a Member instance.
|
|
345
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
338
346
|
cashierUrl: async () => {
|
|
339
347
|
const redirect = await createRedirectSession({
|
|
340
348
|
ecomCheckout: { checkoutId },
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hosted checkout (#4089 B3). A Branded Lite hosted in a host shell (Spaces)
|
|
2
|
+
// pays as the member the host lent it: Headless `createRedirectSession` does not take a Member
|
|
3
|
+
// instance, so the HOST opens the site's checkout signed in as that member. The worker names only
|
|
4
|
+
// its ecom checkout; the host reads Wix's checkout URL, mints a one-time member session and opens
|
|
5
|
+
// the site's `createSessionCookie` → checkout. The session token never reaches this worker.
|
|
6
|
+
|
|
7
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
8
|
+
import { hostSiteFromInput } from "./branded-lite-hosted.js";
|
|
9
|
+
|
|
10
|
+
/** The host verbs (registered by the host shell, never by the app itself). The first prepares the
|
|
11
|
+
* checkout and answers a one-time ticket; the second opens it. Two steps so the caller's charge guard
|
|
12
|
+
* is re-read after the host's network round trips and right before the checkout opens — the prepared
|
|
13
|
+
* URL (which carries the member's session token) stays in the host; only the ticket crosses here. */
|
|
14
|
+
export const HOSTED_CHECKOUT_ACTION = "himi.host.memberCheckout";
|
|
15
|
+
export const HOSTED_CHECKOUT_OPEN_ACTION = "himi.host.memberCheckout.open";
|
|
16
|
+
|
|
17
|
+
/** Whether this worker runs inside a host that opened a site for it. */
|
|
18
|
+
export function isHostedWorker(): boolean {
|
|
19
|
+
return hostSiteFromInput((globalThis as { himalaya?: { input?: unknown } }).himalaya?.input) !== null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type HostAnswer = { opened?: unknown; ticket?: unknown; payload?: { opened?: unknown; ticket?: unknown } } | null;
|
|
23
|
+
|
|
24
|
+
/** `payCashierOrder`'s `openCashier` for a hosted app: the host prepares [checkoutId]'s checkout as the
|
|
25
|
+
* lent member, the caller's guard is re-read, and only then does the host open it. Resolves whether it
|
|
26
|
+
* opened ("withdrawn" when the guard said no); a host without the verbs (or that refused) → false. */
|
|
27
|
+
export function hostedCheckoutOpener(checkoutId: string): (stillMayCharge: () => Promise<boolean>) => Promise<boolean | "withdrawn"> {
|
|
28
|
+
return async (stillMayCharge) => {
|
|
29
|
+
try {
|
|
30
|
+
const prepared = await dispatch(HOSTED_CHECKOUT_ACTION, { checkoutId }) as HostAnswer;
|
|
31
|
+
const ticket = prepared?.ticket ?? prepared?.payload?.ticket;
|
|
32
|
+
if (typeof ticket !== "string" || !ticket) return false;
|
|
33
|
+
// An unopened ticket simply expires in the host: nothing to cancel.
|
|
34
|
+
if (!(await stillMayCharge())) return "withdrawn";
|
|
35
|
+
const result = await dispatch(HOSTED_CHECKOUT_OPEN_ACTION, { ticket }) as HostAnswer;
|
|
36
|
+
const opened = result?.opened ?? result?.payload?.opened;
|
|
37
|
+
return opened === true || opened === "true";
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -9,6 +9,7 @@ import { bookSlot, getService, queryServiceAvailability, type WixBookingSlotFull
|
|
|
9
9
|
import { createCheckout, createOrder } from "@himalaya/wix-ecom";
|
|
10
10
|
import { createRedirectSession, type WixSlot } from "@himalaya/wix-redirects";
|
|
11
11
|
import { payCashierOrder } from "@himalaya/checkout";
|
|
12
|
+
import { hostedCheckoutOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
12
13
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
13
14
|
import { displayName, getMyData, type WixMyData } from "@himalaya/wix-users";
|
|
14
15
|
import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-price.js";
|
|
@@ -662,9 +663,12 @@ const svc = defineService<S, {
|
|
|
662
663
|
// 3. Create the Wix-managed order — mints the cashier snapshot when a
|
|
663
664
|
// balance is due. No paymentGatewayOrderId ⇒ nothing to charge
|
|
664
665
|
// (covered / zero total) ⇒ the booking is already confirmed.
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
666
|
+
// Hosted (Spaces): the site's own checkout page creates the order (as
|
|
667
|
+
// RN does) — creating it here first fails on a site with no payment method set up.
|
|
668
|
+
const hosted = isHostedWorker();
|
|
669
|
+
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
|
+
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
|
+
if (!snapshotId && !hosted) {
|
|
668
672
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
669
673
|
}
|
|
670
674
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -676,6 +680,8 @@ const svc = defineService<S, {
|
|
|
676
680
|
appId: WIX_BOOKINGS_APP_ID,
|
|
677
681
|
snapshotId,
|
|
678
682
|
msid: await resolveMsid(),
|
|
683
|
+
// Hosted (Spaces): the host opens this booking's checkout as the lent member.
|
|
684
|
+
...(hosted ? { openCashier: hostedCheckoutOpener(checkoutId) } : {}),
|
|
679
685
|
cashierUrl: async () => {
|
|
680
686
|
const redirect = await createRedirectSession({
|
|
681
687
|
bookingsCheckout: { slotAvailability: { slot: slot as unknown as WixSlot } },
|