@wix/himalaya-cli 0.1551.0 → 0.1552.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/builder.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-contract.d.ts +2 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +24 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/order-refs.d.ts +12 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/forms/src/extensions.d.ts +83 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +146 -23
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +8 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +147 -24
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-forms.mjs +19 -0
- package/dist/cli.mjs +2455 -2166
- package/fixtures/wix-canned.json +14 -7
- package/guides/getting-started.md +17 -1
- package/guides/headless-loop.md +7 -1
- package/guides/himi-skill.md +17 -1
- package/guides/himi-test.md +95 -7
- package/guides/iap-pricing.md +1 -1
- package/guides/iap-products.md +2 -2
- package/guides/iap-screen-adoption.md +1 -1
- package/guides/index.json +1 -1
- package/guides/sdk-reference.json +82 -4
- package/guides/skill.md +16 -0
- package/package.json +2 -2
- package/templates/beauty-salon/config.ts +13 -0
- package/templates/beauty-salon/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/beauty-salon/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/branded-lite/config.ts +13 -0
- package/templates/branded-lite/dev/index.ts +1338 -2011
- package/templates/branded-lite/tier5-src/_shared/branded-form.ts +262 -0
- package/templates/branded-lite/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/branded-lite/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-form/index.ts +399 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-forms/index.ts +22 -7
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/community-club/config.ts +13 -0
- package/templates/community-club/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/community-club/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/events-meetups/config.ts +13 -0
- package/templates/events-meetups/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/events-meetups/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/gym-fitness/config.ts +13 -0
- package/templates/gym-fitness/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/gym-fitness/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/nonprofit-cause/config.ts +13 -0
- package/templates/nonprofit-cause/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/nonprofit-cause/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/podcast-creator/config.ts +13 -0
- package/templates/podcast-creator/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/podcast-creator/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/portfolio-creative/config.ts +13 -0
- package/templates/portfolio-creative/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/portfolio-creative/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/restaurant/config.ts +13 -0
- package/templates/restaurant/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/restaurant/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/retail-store/config.ts +13 -0
- package/templates/retail-store/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/yoga-studio/config.ts +13 -0
- package/templates/yoga-studio/tier5-src/_shared/iap-attendance-purchase.ts +1 -1
- package/templates/yoga-studio/tier5-src/_shared/iap-worker.ts +1 -1
- package/templates/branded-lite/tier5-src/wix-spaces-form-detail/index.ts +0 -30
|
@@ -781,6 +781,9 @@ export declare function datePicker(props: {
|
|
|
781
781
|
maxUnix?: number;
|
|
782
782
|
mode?: "date" | "time" | "datetime";
|
|
783
783
|
onChange?: ActionShape;
|
|
784
|
+
/** "$service:" binding → unix seconds or an ISO-8601 date; the picker prefills from and
|
|
785
|
+
* tracks it (every renderer reads it; it overrides `valueUnix`). */
|
|
786
|
+
valuePath?: string;
|
|
784
787
|
}, opts?: {
|
|
785
788
|
id?: string;
|
|
786
789
|
}): Component;
|
|
@@ -37,8 +37,8 @@ export interface AppleSaleRule {
|
|
|
37
37
|
appProductId(entityId: string): string;
|
|
38
38
|
productType: "NON_CONSUMABLE" | "CONSUMABLE";
|
|
39
39
|
}
|
|
40
|
-
export declare const BOOKINGS_APPLE_SALES_ENABLED =
|
|
41
|
-
export declare const EVENTS_APPLE_SALES_ENABLED =
|
|
40
|
+
export declare const BOOKINGS_APPLE_SALES_ENABLED = true;
|
|
41
|
+
export declare const EVENTS_APPLE_SALES_ENABLED = true;
|
|
42
42
|
/**
|
|
43
43
|
* Whether Wix Stores items sell through the App Store, through wix-iap StartItemPayment
|
|
44
44
|
* (catalyst-server #24496), which places the member's eCom order for one catalog item. OFF: that RPC
|
|
@@ -97,6 +97,16 @@ export type OrderAttempt = (
|
|
|
97
97
|
noOrderCreated?: true;
|
|
98
98
|
};
|
|
99
99
|
export type AccessRead = "granted" | "pending" | "none" | "unavailable" | "sessionChanged";
|
|
100
|
+
/** What a repeatable sale stores before an inventory write whose answer may be lost: the ids it
|
|
101
|
+
* targets or created, and when Wix will itself have released anything it created. */
|
|
102
|
+
export interface OpeningGuard {
|
|
103
|
+
verticalRef?: VerticalRef;
|
|
104
|
+
releaseAt?: number;
|
|
105
|
+
}
|
|
106
|
+
/** `released`: nothing the guarded write may have created can be sold twice, so the guard goes.
|
|
107
|
+
* `held`: still unknown, and it blocks this sale. `unrelated`: still unknown, but it targets other
|
|
108
|
+
* inventory than this sale's. */
|
|
109
|
+
export type OpeningResolution = "released" | "held" | "unrelated" | "unavailable" | "sessionChanged";
|
|
100
110
|
/** An item wix-iap can order itself (StartItemPayment): the item as eCom's catalog reference, and
|
|
101
111
|
* how the adapter finds the eCom order that call places again. */
|
|
102
112
|
export interface ItemPayment {
|
|
@@ -113,8 +123,18 @@ export interface IapOrderAdapter {
|
|
|
113
123
|
eligibility(item: IapOrderItem): IapEligibility;
|
|
114
124
|
/** Opens, or reuses the vertical's own open, order for the signed-in member. */
|
|
115
125
|
/** Repeatable adapters call beforeCreate immediately before their first inventory write,
|
|
116
|
-
* after read-only checks, and abort without writing if it returns false.
|
|
117
|
-
|
|
126
|
+
* after read-only checks, and abort without writing if it returns false. They call afterCreate
|
|
127
|
+
* with the ids of each inventory write as soon as it answers, so a later failure can be undone. */
|
|
128
|
+
openOrder(item: IapOrderItem, bridge: SessionBoundBridge, beforeCreate?: (guard: OpeningGuard) => boolean, afterCreate?: (guard: OpeningGuard) => void): Promise<OrderAttempt>;
|
|
129
|
+
/** Settles an earlier attempt's guard before a new sale of the same item. `settled`: the attempt
|
|
130
|
+
* that wrote it has had time to finish, so what it created may be undone; before then it may be
|
|
131
|
+
* another screen's sale still in flight. `claim` must answer true immediately before anything
|
|
132
|
+
* is undone: it takes the guard from that sale, which is then never charged. With no item (on
|
|
133
|
+
* entry, not a sale) only `released` matters. Without it, a guard holds its item until its `releaseAt`. */
|
|
134
|
+
resolveOpening?(guard: OpeningGuard, item: IapOrderItem | undefined, bridge: SessionBoundBridge, options: {
|
|
135
|
+
settled: boolean;
|
|
136
|
+
claim(): boolean;
|
|
137
|
+
}): Promise<OpeningResolution>;
|
|
118
138
|
/** Re-reads an order opened earlier; `open` only while it can still be paid. */
|
|
119
139
|
reopenOrder(order: {
|
|
120
140
|
cashierOrderId: string;
|
|
@@ -157,6 +177,8 @@ export interface OrderRef {
|
|
|
157
177
|
appleTransactionId?: string;
|
|
158
178
|
/** The StoreKit token StartPayment minted for this payment (D61): recovery finds the order by it. */
|
|
159
179
|
appAccountToken?: string;
|
|
180
|
+
/** For `openingOrder`: when anything its write created has been released by Wix. */
|
|
181
|
+
releaseAt?: number;
|
|
160
182
|
updatedAt: number;
|
|
161
183
|
}
|
|
162
184
|
export interface OrderRefPartition {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OrderRefPartition, OrderRefStore } from "./apple-iap-contract.js";
|
|
1
|
+
import type { IapOrderAdapter, IapOrderItem, OpeningResolution, OrderRef, OrderRefPartition, OrderRefStore, SessionBoundBridge } from "./apple-iap-contract.js";
|
|
2
2
|
export interface KeyValueStorage {
|
|
3
3
|
getItem(key: string): string | null;
|
|
4
4
|
setItem(key: string, value: string): void;
|
|
@@ -12,9 +12,18 @@ export declare const NEEDS_SUPPORT_HOLD_MS = 604800000;
|
|
|
12
12
|
export declare const ITEM_START_HOLD_MS = 3600000;
|
|
13
13
|
/** Drops every hold older than its stage's hold time, whatever its key (an item, or a `payment:`
|
|
14
14
|
* with no local order), so holds never accumulate and lock the member out. A held proof still
|
|
15
|
-
* unfinished renews its hold on every retry, so only one Apple no longer delivers expires.
|
|
16
|
-
* the keys it removed. */
|
|
15
|
+
* unfinished renews its hold on every retry, so only one Apple no longer delivers expires. A
|
|
16
|
+
* creation guard goes at its own `releaseAt`. Returns the keys it removed. */
|
|
17
17
|
export declare function pruneExpiredHolds(partition: OrderRefPartition, now: number): string[];
|
|
18
|
+
/** How long (5 minutes) a creation guard may belong to a sale still running in another screen's
|
|
19
|
+
* worker, which shares these references but not that sale's coordinator: longer than any one
|
|
20
|
+
* openOrder takes. Until then nothing it may have created is undone. A literal, as above. */
|
|
21
|
+
export declare const OPENING_SETTLE_MS = 300000;
|
|
22
|
+
/** Asks the guard's adapter to settle it. Before undoing anything the adapter claims the guard
|
|
23
|
+
* (restamps it), so the sale that wrote it, should it still be running, is no longer charged. It
|
|
24
|
+
* is dropped only while it is still the stored guard: a slow answer never removes what another
|
|
25
|
+
* worker wrote under the key since. A guard changed meanwhile is judged again as it now is. */
|
|
26
|
+
export declare function settleOpening(partition: OrderRefPartition, adapter: IapOrderAdapter, guard: OrderRef, item: IapOrderItem | undefined, bridge: SessionBoundBridge, now: number): Promise<OpeningResolution | "storageUnavailable">;
|
|
18
27
|
/** References one member keeps at once. When full, the oldest reference from before Apple's sheet
|
|
19
28
|
* is evicted; a partition full of handed-over payments refuses new sales instead. */
|
|
20
29
|
export declare const MAX_ORDER_REFS = 16;
|
|
@@ -1 +1,83 @@
|
|
|
1
|
-
|
|
1
|
+
import { type WixCallOptions, type WixSubmission } from "./index.js";
|
|
2
|
+
export interface WixFormSubmissionInput {
|
|
3
|
+
formId: string;
|
|
4
|
+
/** Keyed by each field's `target`; the value shape follows the field's `inputType`
|
|
5
|
+
* ("About Submission Values"). A key that is no field's target fails the whole submission. */
|
|
6
|
+
submissions: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface WixCreateSubmissionRequest {
|
|
9
|
+
submission: WixFormSubmissionInput;
|
|
10
|
+
captchaToken?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface WixCreateSubmissionResponse {
|
|
13
|
+
submission?: WixSubmission;
|
|
14
|
+
}
|
|
15
|
+
export interface WixSubmissionValidationError {
|
|
16
|
+
/** The field's `target`. */
|
|
17
|
+
errorPath?: string;
|
|
18
|
+
errorType?: string;
|
|
19
|
+
errorMessage?: string;
|
|
20
|
+
params?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
export interface WixValidateFormSubmissionResponse {
|
|
23
|
+
valid?: boolean;
|
|
24
|
+
violationErrors?: Array<{
|
|
25
|
+
name?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
ruleName?: string;
|
|
28
|
+
submissionValidationErrors?: {
|
|
29
|
+
errors?: WixSubmissionValidationError[];
|
|
30
|
+
};
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
/** The endpoint answered: `value` is what the call returns without `{ offline: "queue" }`. */
|
|
34
|
+
export interface WixSent<T> {
|
|
35
|
+
status: "sent";
|
|
36
|
+
value: T;
|
|
37
|
+
}
|
|
38
|
+
/** The write waits in the device's offline outbox; `writeId` names it in
|
|
39
|
+
* `wixApi.offline` events. */
|
|
40
|
+
export interface WixQueued {
|
|
41
|
+
status: "queued";
|
|
42
|
+
writeId: string;
|
|
43
|
+
tag: string;
|
|
44
|
+
}
|
|
45
|
+
export type WixOfflineResult<T> = WixSent<T> | WixQueued;
|
|
46
|
+
/** Per-call options of a write the runtime may queue offline. `offline: "queue"` opts this ONE
|
|
47
|
+
* call into the outbox, and the answer becomes a `WixOfflineResult<T>`. It queues only if the
|
|
48
|
+
* app declares a `queueOffline` cache rule for the endpoint; a form send has no server-side
|
|
49
|
+
* dedupe (`unsentOnly`), so on web it is refused offline (`err.code === "offline_write_blocked"`). */
|
|
50
|
+
export interface WixQueueCallOptions extends WixCallOptions {
|
|
51
|
+
offline?: "queue";
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sends a filled form. Creates a submission (and, through the form's contact mapping, a
|
|
55
|
+
* contact) on the site, so call it only on the submitter's explicit action. An anonymous
|
|
56
|
+
* visitor may call it. Keys of `submissions` are field targets; Wix rejects the whole
|
|
57
|
+
* submission for an unknown key or an invalid value, with per-field `submissionValidationErrors`.
|
|
58
|
+
* With `{ offline: "queue" }` the answer is an envelope: `sent`, or `queued` while the device is
|
|
59
|
+
* offline (native only — on web it is refused offline with `code: "offline_write_blocked"`).
|
|
60
|
+
*
|
|
61
|
+
* POST /form-submission-service/v4/submissions
|
|
62
|
+
*/
|
|
63
|
+
export declare function createSubmission(req: WixCreateSubmissionRequest, opts: WixQueueCallOptions & {
|
|
64
|
+
offline: "queue";
|
|
65
|
+
}): Promise<WixOfflineResult<WixCreateSubmissionResponse>>;
|
|
66
|
+
/**
|
|
67
|
+
* Sends a filled form. Creates a submission (and, through the form's contact mapping, a
|
|
68
|
+
* contact) on the site, so call it only on the submitter's explicit action. An anonymous
|
|
69
|
+
* visitor may call it. Keys of `submissions` are field targets; Wix rejects the whole
|
|
70
|
+
* submission for an unknown key or an invalid value, with per-field `submissionValidationErrors`.
|
|
71
|
+
* With `{ offline: "queue" }` the answer is an envelope: `sent`, or `queued` while the device is
|
|
72
|
+
* offline (native only — on web it is refused offline with `code: "offline_write_blocked"`).
|
|
73
|
+
*
|
|
74
|
+
* POST /form-submission-service/v4/submissions
|
|
75
|
+
*/
|
|
76
|
+
export declare function createSubmission(req: WixCreateSubmissionRequest, opts?: WixCallOptions): Promise<WixCreateSubmissionResponse>;
|
|
77
|
+
/**
|
|
78
|
+
* Checks a filled form against the form's rules without creating anything. Answers
|
|
79
|
+
* `valid: false` with one `submissionValidationErrors.errors[]` entry per failed value.
|
|
80
|
+
*
|
|
81
|
+
* POST /form-submission-service/v4/submissions/validate
|
|
82
|
+
*/
|
|
83
|
+
export declare function validateFormSubmission(req: WixCreateSubmissionRequest, opts?: WixCallOptions): Promise<WixValidateFormSubmissionResponse>;
|
|
@@ -687,8 +687,8 @@ var sameReference = (value, reference) => isObject2(value) && value.kind === ref
|
|
|
687
687
|
|
|
688
688
|
// ../../core/sdk/iap/src/wix-payments-contract.ts
|
|
689
689
|
var HIMALAYA_SERVE_IAP_ROUTE = { prefix: "/himalaya-serve/v1/iap" };
|
|
690
|
-
var BOOKINGS_APPLE_SALES_ENABLED =
|
|
691
|
-
var EVENTS_APPLE_SALES_ENABLED =
|
|
690
|
+
var BOOKINGS_APPLE_SALES_ENABLED = true;
|
|
691
|
+
var EVENTS_APPLE_SALES_ENABLED = true;
|
|
692
692
|
var ATTENDANCE_SALE_RULE = { appProductId: (id) => id, productType: "CONSUMABLE" };
|
|
693
693
|
var STORES_ITEM_PAYMENT_ENABLED = false;
|
|
694
694
|
var STORES_APPLE_SALES_ENABLED = true;
|
|
@@ -1428,10 +1428,13 @@ function locationType(raw) {
|
|
|
1428
1428
|
return type === "CUSTOM" && addresses.every(describesNoPlace) ? ADDRESSLESS_CUSTOM : type;
|
|
1429
1429
|
}
|
|
1430
1430
|
function describesNoPlace(address) {
|
|
1431
|
-
const parts = ["country", "subdivision", "city", "postalCode", "
|
|
1431
|
+
const parts = ["country", "subdivision", "city", "postalCode", "addressLine2", "streetAddress", "location"];
|
|
1432
1432
|
if (parts.some((key) => address[key] !== void 0 && address[key] !== "")) return false;
|
|
1433
|
-
|
|
1434
|
-
|
|
1433
|
+
return [address.addressLine, address.formattedAddress].every((value) => {
|
|
1434
|
+
if (value !== void 0 && typeof value !== "string") return false;
|
|
1435
|
+
const description = value?.trim() ?? "";
|
|
1436
|
+
return description === "" || ONLINE_LABEL.test(description);
|
|
1437
|
+
});
|
|
1435
1438
|
}
|
|
1436
1439
|
var ONLINE_LABEL = /^(online|virtual)(\s+(class|classes|classroom|course|session|sessions|meeting|lesson|training|workshop|event))?$/i;
|
|
1437
1440
|
function ticketAttendanceOf(event, definition) {
|
|
@@ -1701,9 +1704,33 @@ function isFinalRefusal(status) {
|
|
|
1701
1704
|
var NEEDS_SUPPORT_HOLD_MS = 6048e5;
|
|
1702
1705
|
var ITEM_START_HOLD_MS = 36e5;
|
|
1703
1706
|
function pruneExpiredHolds(partition, now) {
|
|
1704
|
-
const expired = partition.refs().filter((ref) => now - ref.updatedAt >= (HOLD_MS[ref.stage] ?? Infinity));
|
|
1707
|
+
const expired = partition.refs().filter((ref) => now - ref.updatedAt >= (HOLD_MS[ref.stage] ?? Infinity) || released(ref, now));
|
|
1705
1708
|
return expired.filter((ref) => partition.remove(ref.key)).map((ref) => ref.key);
|
|
1706
1709
|
}
|
|
1710
|
+
var OPENING_SETTLE_MS = 3e5;
|
|
1711
|
+
async function settleOpening(partition, adapter, guard, item, bridge, now) {
|
|
1712
|
+
const resolve = adapter.resolveOpening;
|
|
1713
|
+
if (!resolve) return "held";
|
|
1714
|
+
let current = guard;
|
|
1715
|
+
const claim = () => {
|
|
1716
|
+
const next = { ...current, updatedAt: now };
|
|
1717
|
+
if (!isStoredGuard(partition, current) || !partition.put(next)) return false;
|
|
1718
|
+
current = next;
|
|
1719
|
+
return true;
|
|
1720
|
+
};
|
|
1721
|
+
const resolution = await resolve(guard, item, bridge, { settled: now - guard.updatedAt >= OPENING_SETTLE_MS, claim });
|
|
1722
|
+
if (isStoredGuard(partition, current)) {
|
|
1723
|
+
if (resolution !== "released") return resolution;
|
|
1724
|
+
return partition.remove(guard.key) ? "released" : "storageUnavailable";
|
|
1725
|
+
}
|
|
1726
|
+
const stored = partition.refs().find((ref) => ref.key === guard.key);
|
|
1727
|
+
if (!stored) return "released";
|
|
1728
|
+
return stored.stage === "openingOrder" ? resolve(stored, item, bridge, { settled: false, claim: () => false }) : "held";
|
|
1729
|
+
}
|
|
1730
|
+
function isStoredGuard(partition, guard) {
|
|
1731
|
+
const stored = partition.refs().find((ref) => ref.key === guard.key);
|
|
1732
|
+
return stored?.stage === "openingOrder" && stored.updatedAt === guard.updatedAt;
|
|
1733
|
+
}
|
|
1707
1734
|
var MAX_ORDER_REFS = 16;
|
|
1708
1735
|
function createWorkerOrderRefStore(storage) {
|
|
1709
1736
|
const kv = () => storage ?? hostStorage();
|
|
@@ -1780,10 +1807,14 @@ function writeVerified(store, location, value) {
|
|
|
1780
1807
|
function isOrderRef(value) {
|
|
1781
1808
|
if (!isObject6(value) || typeof value.key !== "string" || !STAGES.has(value.stage)) return false;
|
|
1782
1809
|
if (typeof value.updatedAt !== "number") return false;
|
|
1810
|
+
if (value.releaseAt !== void 0 && typeof value.releaseAt !== "number") return false;
|
|
1783
1811
|
const optional = ["kind", "cashierOrderId", "wixTransactionId", "paymentId", "storeProductId", "appProductId", "appleTransactionId", "appAccountToken"];
|
|
1784
1812
|
if (!optional.every((field) => value[field] === void 0 || typeof value[field] === "string")) return false;
|
|
1785
1813
|
return value.verticalRef === void 0 || isStringMap(value.verticalRef);
|
|
1786
1814
|
}
|
|
1815
|
+
function released(ref, now) {
|
|
1816
|
+
return ref.stage === "openingOrder" && ref.releaseAt !== void 0 && now >= ref.releaseAt;
|
|
1817
|
+
}
|
|
1787
1818
|
function isPartitionKey(key) {
|
|
1788
1819
|
return isUUID3(key.purchasesAppId) && isUUID3(key.siteId) && isUUID3(key.memberId);
|
|
1789
1820
|
}
|
|
@@ -1920,6 +1951,8 @@ function createWixOrderBackend(deps) {
|
|
|
1920
1951
|
async function getPurchaseContext(session, catalogRef) {
|
|
1921
1952
|
const sale = await saleFor(session, catalogRef);
|
|
1922
1953
|
if (isStop(sale)) return contextResult(catalogRef, sale);
|
|
1954
|
+
const unresolved = await resolveOpenings(sale);
|
|
1955
|
+
if (unresolved) return contextResult(catalogRef, unresolved);
|
|
1923
1956
|
const blocked = saleBlocked(sale);
|
|
1924
1957
|
if (blocked) return contextResult(catalogRef, blocked);
|
|
1925
1958
|
const itemPayment2 = deps.itemPaymentEnabled ? sale.adapter.itemPayment?.(sale.item) : null;
|
|
@@ -1938,11 +1971,26 @@ function createWixOrderBackend(deps) {
|
|
|
1938
1971
|
if (failure3) return stopWith("rejected", failure3);
|
|
1939
1972
|
if (sale.adapter.repeatable) {
|
|
1940
1973
|
const prefix = `${sale.item.reference.kind}:${sale.item.reference.id}#`;
|
|
1941
|
-
const unresolved = sale.partition.refs().find((ref) => ref.key.startsWith(prefix) && ["openingOrder", "held", "needsSupport"].includes(ref.stage));
|
|
1942
|
-
if (unresolved) return stopWith("rejected", unresolved.stage === "openingOrder" ? "
|
|
1974
|
+
const unresolved = sale.partition.refs().find((ref) => ref.key.startsWith(prefix) && !sale.unrelated.has(ref.key) && ["openingOrder", "held", "needsSupport"].includes(ref.stage));
|
|
1975
|
+
if (unresolved) return stopWith("rejected", unresolved.stage === "openingOrder" ? "paymentInProgress" : "needsSupport");
|
|
1943
1976
|
}
|
|
1944
1977
|
return deps.productBusy?.(sale.appleProduct.productId) ? stopWith("rejected", "paymentInProgress") : null;
|
|
1945
1978
|
}
|
|
1979
|
+
async function resolveOpenings(sale) {
|
|
1980
|
+
if (!sale.adapter.repeatable || !sale.adapter.resolveOpening) return null;
|
|
1981
|
+
for (const guard of openingsOf(sale)) {
|
|
1982
|
+
const resolution = await settleOpening(sale.partition, sale.adapter, guard, sale.item, sale.bridge, now());
|
|
1983
|
+
if (!sale.bridge.isCurrent() || resolution === "sessionChanged") return STALE2;
|
|
1984
|
+
if (resolution === "unavailable") return retry("unavailable");
|
|
1985
|
+
if (resolution === "storageUnavailable") return stopWith("rejected", "storageUnavailable");
|
|
1986
|
+
if (resolution === "unrelated") sale.unrelated.add(guard.key);
|
|
1987
|
+
}
|
|
1988
|
+
return null;
|
|
1989
|
+
}
|
|
1990
|
+
function openingsOf(sale) {
|
|
1991
|
+
const prefix = `${sale.item.reference.kind}:${sale.item.reference.id}#`;
|
|
1992
|
+
return sale.partition.refs().filter((ref) => ref.stage === "openingOrder" && ref.key.startsWith(prefix));
|
|
1993
|
+
}
|
|
1946
1994
|
async function saleFor(session, catalogRef) {
|
|
1947
1995
|
const sold = deps.itemFor(catalogRef);
|
|
1948
1996
|
const adapter = sold && adapterFor(sold.item.reference.kind);
|
|
@@ -1963,13 +2011,15 @@ function createWixOrderBackend(deps) {
|
|
|
1963
2011
|
adapter,
|
|
1964
2012
|
member,
|
|
1965
2013
|
partition: member.partition,
|
|
1966
|
-
bridge: bindBridge(session, deps.session, deps.bridge)
|
|
2014
|
+
bridge: bindBridge(session, deps.session, deps.bridge),
|
|
2015
|
+
unrelated: /* @__PURE__ */ new Set()
|
|
1967
2016
|
};
|
|
1968
2017
|
}
|
|
1969
2018
|
async function orderFor(sale) {
|
|
1970
2019
|
const existing = refAt(sale.partition, sale.catalogRef);
|
|
1971
2020
|
let prevented;
|
|
1972
|
-
|
|
2021
|
+
let guarded;
|
|
2022
|
+
const beforeCreate = (guard = {}) => {
|
|
1973
2023
|
if (!sale.adapter.repeatable || existing) return true;
|
|
1974
2024
|
if (!sale.bridge.isCurrent()) {
|
|
1975
2025
|
prevented = STALE2;
|
|
@@ -1980,18 +2030,30 @@ function createWixOrderBackend(deps) {
|
|
|
1980
2030
|
prevented = blocked;
|
|
1981
2031
|
return false;
|
|
1982
2032
|
}
|
|
1983
|
-
const opening = persist(sale, { key: sale.catalogRef, kind: sale.adapter.kind, stage: "openingOrder", updatedAt: now() });
|
|
2033
|
+
const opening = persist(sale, { ...guard, key: sale.catalogRef, kind: sale.adapter.kind, stage: "openingOrder", updatedAt: now() });
|
|
1984
2034
|
if (isStop(opening)) {
|
|
1985
2035
|
prevented = opening;
|
|
1986
2036
|
return false;
|
|
1987
2037
|
}
|
|
2038
|
+
guarded = opening.updatedAt;
|
|
1988
2039
|
return true;
|
|
1989
2040
|
};
|
|
1990
|
-
const
|
|
2041
|
+
const afterCreate = (guard) => {
|
|
2042
|
+
const opening = refAt(sale.partition, sale.catalogRef);
|
|
2043
|
+
if (opening?.stage !== "openingOrder" || opening.updatedAt !== guarded) return;
|
|
2044
|
+
const recorded = persist(sale, { ...opening, ...guard, verticalRef: { ...opening.verticalRef, ...guard.verticalRef }, updatedAt: now() });
|
|
2045
|
+
if (!isStop(recorded)) guarded = recorded.updatedAt;
|
|
2046
|
+
};
|
|
2047
|
+
const attempt3 = existing?.cashierOrderId && existing.verticalRef ? await reopenOrOpen(sale, { cashierOrderId: existing.cashierOrderId, verticalRef: existing.verticalRef }) : await sale.adapter.openOrder(sale.item, sale.bridge, beforeCreate, afterCreate);
|
|
1991
2048
|
if (prevented) return prevented;
|
|
2049
|
+
if (guarded !== void 0 && attempt3.status === "open" && !stillGuarded(sale, guarded)) return retry("unavailable");
|
|
1992
2050
|
const ref = recordOrder(sale, existing, attempt3);
|
|
1993
2051
|
return isStop(ref) ? ref : { ref, placed: isPlaced(attempt3) };
|
|
1994
2052
|
}
|
|
2053
|
+
function stillGuarded(sale, guarded) {
|
|
2054
|
+
const stored = refAt(sale.partition, sale.catalogRef);
|
|
2055
|
+
return stored?.stage === "openingOrder" && stored.updatedAt === guarded;
|
|
2056
|
+
}
|
|
1995
2057
|
async function reopenOrOpen(sale, order) {
|
|
1996
2058
|
const reopened = await sale.adapter.reopenOrder(order, sale.bridge);
|
|
1997
2059
|
const closed = reopened.status === "refused" && reopened.reason === "orderClosed";
|
|
@@ -2234,8 +2296,9 @@ var NOT_CONFIGURED = { stop: true, result: "rejected", failure: "notConfigured"
|
|
|
2234
2296
|
var UNAVAILABLE = { stop: true, result: "retryable", failure: "unavailable" };
|
|
2235
2297
|
var OUTCOME_UNKNOWN = { stop: true, result: "rejected", failure: "outcomeUnknown" };
|
|
2236
2298
|
var BLOCKING_STAGES = {
|
|
2299
|
+
// A repeatable sale's guard settles on a later tap, so it keeps the action tappable.
|
|
2237
2300
|
startingItem: "outcomeUnknown",
|
|
2238
|
-
openingOrder: "
|
|
2301
|
+
openingOrder: "paymentInProgress",
|
|
2239
2302
|
submitted: "paymentInProgress",
|
|
2240
2303
|
held: "paymentHeld",
|
|
2241
2304
|
needsSupport: "needsSupport"
|
|
@@ -2494,6 +2557,7 @@ function enabledCheckout(deps) {
|
|
|
2494
2557
|
if (!tracked) return backOffDue();
|
|
2495
2558
|
partitionRead = null;
|
|
2496
2559
|
for (const key of pruneExpiredHolds(tracked.partition, deps.clock.now())) payments.delete(key);
|
|
2560
|
+
if (!options.dueOnly) await settleOpenings(session, tracked.partition);
|
|
2497
2561
|
for (const ref of tracked.partition.refs()) {
|
|
2498
2562
|
if (!isCurrent(session)) return;
|
|
2499
2563
|
if (ref.stage === "needsSupport") setPayment(ref.key, "needsSupport");
|
|
@@ -2509,6 +2573,13 @@ function enabledCheckout(deps) {
|
|
|
2509
2573
|
}
|
|
2510
2574
|
publish();
|
|
2511
2575
|
}
|
|
2576
|
+
async function settleOpenings(session, partition) {
|
|
2577
|
+
for (const ref of partition.refs()) {
|
|
2578
|
+
const adapter = deps.adapters.find((candidate) => candidate.kind === ref.kind);
|
|
2579
|
+
if (ref.stage !== "openingOrder" || !adapter?.resolveOpening || !isCurrent(session)) continue;
|
|
2580
|
+
await settleOpening(partition, adapter, ref, void 0, bindBridge(session, deps.session, bridge), deps.clock.now());
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2512
2583
|
async function trackedPartition(session) {
|
|
2513
2584
|
const binding = await bindingOf(deps.binding);
|
|
2514
2585
|
if (!binding || !isCurrent(session)) return binding === null ? "none" : null;
|
|
@@ -3322,6 +3393,12 @@ var BOOKING = "bookingsService";
|
|
|
3322
3393
|
var TICKET = "eventsTicket";
|
|
3323
3394
|
var NOT_ENABLED = { status: "refused", reason: "notEnabled" };
|
|
3324
3395
|
var CHANGED = { status: "refused", reason: "productChanged" };
|
|
3396
|
+
var MINUTE_MS = 6e4;
|
|
3397
|
+
var RELEASE_MARGIN_MS = 3e5;
|
|
3398
|
+
var DEFAULT_RESERVATION_MINUTES = 60;
|
|
3399
|
+
var PAYMENT_TAKEN = ["PAID", "PARTIALLY_PAID", "EXEMPT", "REFUNDED"];
|
|
3400
|
+
var HAS_OFFSET = /(?:Z|[+-]\d{2}:?\d{2})$/i;
|
|
3401
|
+
var LATEST_ZONE_MS = 432e5;
|
|
3325
3402
|
function attendanceOrdersWith(options) {
|
|
3326
3403
|
const now = options.now ?? Date.now;
|
|
3327
3404
|
return {
|
|
@@ -3329,7 +3406,8 @@ function attendanceOrdersWith(options) {
|
|
|
3329
3406
|
kind: BOOKING,
|
|
3330
3407
|
repeatable: true,
|
|
3331
3408
|
eligibility: (item) => eligible(item, BOOKING, options.bookingsEnabled),
|
|
3332
|
-
openOrder: (item, bridge, beforeCreate) => options.bookingsEnabled ? openBooking(item, bridge, beforeCreate) : Promise.resolve(NOT_ENABLED),
|
|
3409
|
+
openOrder: (item, bridge, beforeCreate, afterCreate) => options.bookingsEnabled ? openBooking(item, bridge, beforeCreate, afterCreate) : Promise.resolve(NOT_ENABLED),
|
|
3410
|
+
resolveOpening: resolveBookingOpening,
|
|
3333
3411
|
readAccess: bookingAccess,
|
|
3334
3412
|
reopenOrder: (order, bridge) => reopen(order, bridge, bookingAccess)
|
|
3335
3413
|
},
|
|
@@ -3337,7 +3415,7 @@ function attendanceOrdersWith(options) {
|
|
|
3337
3415
|
kind: TICKET,
|
|
3338
3416
|
repeatable: true,
|
|
3339
3417
|
eligibility: (item) => eligible(item, TICKET, options.eventsEnabled),
|
|
3340
|
-
openOrder: (item, bridge, beforeCreate) => options.eventsEnabled ? openTicket(item, bridge, now, beforeCreate) : Promise.resolve(NOT_ENABLED),
|
|
3418
|
+
openOrder: (item, bridge, beforeCreate, afterCreate) => options.eventsEnabled ? openTicket(item, bridge, now, beforeCreate, afterCreate) : Promise.resolve(NOT_ENABLED),
|
|
3341
3419
|
readAccess: ticketAccess,
|
|
3342
3420
|
reopenOrder: (order, bridge) => reopen(order, bridge, ticketAccess, now)
|
|
3343
3421
|
}
|
|
@@ -3350,7 +3428,7 @@ function eligible(item, kind, enabled) {
|
|
|
3350
3428
|
const selection = kind === BOOKING ? item.attendance.booking : item.attendance.ticket;
|
|
3351
3429
|
return selection ? { eligible: true } : UNSUPPORTED;
|
|
3352
3430
|
}
|
|
3353
|
-
async function openBooking(item, bridge, beforeCreate) {
|
|
3431
|
+
async function openBooking(item, bridge, beforeCreate, afterCreate) {
|
|
3354
3432
|
if (!eligible(item, BOOKING, true).eligible) return notCreated(ORDER_REFUSED);
|
|
3355
3433
|
const selected = item.attendance.booking;
|
|
3356
3434
|
if (selected.slot.serviceId !== item.reference.id || !isNonEmpty3(selected.slot.startDate) || !isNonEmpty3(selected.slot.endDate)) return notCreated(ORDER_REFUSED);
|
|
@@ -3364,11 +3442,49 @@ async function openBooking(item, bridge, beforeCreate) {
|
|
|
3364
3442
|
if (isRefusal(availability)) return notCreated(attemptRefused(availability));
|
|
3365
3443
|
const entries = isObject7(availability.body) ? availability.body.availabilityEntries : void 0;
|
|
3366
3444
|
if (!Array.isArray(entries) || !entries.some((entry) => isObject7(entry) && entry.bookable === true && matchesSlot(entry.slot, selected.slot))) return notCreated(CHANGED);
|
|
3367
|
-
if (beforeCreate && !beforeCreate()) return notCreated({ status: "refused", reason: "storageUnavailable" });
|
|
3445
|
+
if (beforeCreate && !beforeCreate(slotGuard(selected.slot))) return notCreated({ status: "refused", reason: "storageUnavailable" });
|
|
3368
3446
|
const created = await bridge.call("POST", "/bookings/v2/bookings", { booking: { bookedEntity: { slot: selected.slot }, contactDetails: selected.contactDetails, totalParticipants: 1, selectedPaymentOption: "ONLINE", ...selected.formInfo ? { formInfo: selected.formInfo } : {} } });
|
|
3369
3447
|
if (isRefusal(created)) return creationRefused(created);
|
|
3370
3448
|
const bookingId = bodyObject(created, "booking")?.id;
|
|
3371
|
-
|
|
3449
|
+
if (!isNonEmpty3(bookingId)) return ORDER_REFUSED;
|
|
3450
|
+
afterCreate?.({ verticalRef: { bookingId } });
|
|
3451
|
+
return bookingCheckout(item, bookingId, bridge);
|
|
3452
|
+
}
|
|
3453
|
+
function slotGuard(slot) {
|
|
3454
|
+
const verticalRef = {};
|
|
3455
|
+
for (const key of ["sessionId", "startDate"]) if (isNonEmpty3(slot[key])) verticalRef[key] = slot[key];
|
|
3456
|
+
const ends = latestInstant(String(slot.endDate));
|
|
3457
|
+
return Number.isFinite(ends) ? { verticalRef, releaseAt: ends + RELEASE_MARGIN_MS } : { verticalRef };
|
|
3458
|
+
}
|
|
3459
|
+
function latestInstant(value) {
|
|
3460
|
+
if (HAS_OFFSET.test(value)) return Date.parse(value);
|
|
3461
|
+
return Date.parse(`${value}Z`) + LATEST_ZONE_MS;
|
|
3462
|
+
}
|
|
3463
|
+
async function resolveBookingOpening(guard, item, bridge, options) {
|
|
3464
|
+
const scope = sameSlot(guard.verticalRef, item?.attendance?.booking?.slot) ? "held" : "unrelated";
|
|
3465
|
+
const bookingId = guard.verticalRef?.bookingId;
|
|
3466
|
+
if (!bookingId || !options.settled) return scope;
|
|
3467
|
+
const released2 = await releaseBooking(bookingId, bridge, options.claim);
|
|
3468
|
+
return released2 === "held" || released2 === "unavailable" && scope === "unrelated" ? scope : released2;
|
|
3469
|
+
}
|
|
3470
|
+
async function releaseBooking(bookingId, bridge, claim) {
|
|
3471
|
+
const read2 = await bridge.call("POST", "/bookings/v2/bookings/query", { query: { filter: { id: { $eq: bookingId } } } });
|
|
3472
|
+
if (isRefusal(read2)) return read2.status === "http" && read2.httpStatus === 404 ? "released" : openingRefused(read2);
|
|
3473
|
+
const rows = isObject7(read2.body) ? read2.body.bookings : void 0;
|
|
3474
|
+
const booking = Array.isArray(rows) ? rows.find((b) => isObject7(b) && b.id === bookingId) : void 0;
|
|
3475
|
+
if (!isObject7(booking)) return "held";
|
|
3476
|
+
if (["CANCELED", "CANCELLED", "DECLINED"].includes(String(booking.status)) || PAYMENT_TAKEN.includes(String(booking.paymentStatus))) return "released";
|
|
3477
|
+
if (booking.status !== "CREATED" || !claim()) return "held";
|
|
3478
|
+
const cancelled = await bridge.call("POST", `/bookings/v2/bookings/${encodeURIComponent(bookingId)}/cancel`, { participantNotification: { notifyParticipants: false }, revision: booking.revision });
|
|
3479
|
+
return isRefusal(cancelled) ? openingRefused(cancelled) : "released";
|
|
3480
|
+
}
|
|
3481
|
+
function openingRefused(refusal) {
|
|
3482
|
+
if (refusal.status === "sessionChanged") return "sessionChanged";
|
|
3483
|
+
return refusal.status === "unavailable" ? "unavailable" : "held";
|
|
3484
|
+
}
|
|
3485
|
+
function sameSlot(guarded, slot) {
|
|
3486
|
+
if (!guarded || !slot) return true;
|
|
3487
|
+
return guarded.sessionId === slot.sessionId && Date.parse(guarded.startDate ?? "") === Date.parse(String(slot.startDate));
|
|
3372
3488
|
}
|
|
3373
3489
|
async function bookingCheckout(item, bookingId, bridge) {
|
|
3374
3490
|
const checkout = await bridge.call("POST", "/ecom/v1/checkouts", { lineItems: [{ quantity: 1, catalogReference: { appId: "13d21c63-b5ec-5912-8397-c3a5ddb27a97", catalogItemId: bookingId } }], channelType: "OTHER_PLATFORM" });
|
|
@@ -3397,7 +3513,7 @@ async function bookingAccess(ref, bridge) {
|
|
|
3397
3513
|
if (booking.status === "CANCELED" || booking.status === "CANCELLED" || booking.status === "DECLINED") return "none";
|
|
3398
3514
|
return payment === "PAID" && booking.status === "CONFIRMED" && booking.paymentStatus === "PAID" ? "granted" : "pending";
|
|
3399
3515
|
}
|
|
3400
|
-
async function openTicket(item, bridge, now, beforeCreate) {
|
|
3516
|
+
async function openTicket(item, bridge, now, beforeCreate, afterCreate) {
|
|
3401
3517
|
if (!eligible(item, TICKET, true).eligible) return notCreated(ORDER_REFUSED);
|
|
3402
3518
|
const selected = item.attendance.ticket;
|
|
3403
3519
|
if (!isNonEmpty3(selected.eventId)) return notCreated(ORDER_REFUSED);
|
|
@@ -3408,16 +3524,23 @@ async function openTicket(item, bridge, now, beforeCreate) {
|
|
|
3408
3524
|
const definitions = isObject7(available.body) ? available.body.definitions : void 0;
|
|
3409
3525
|
const live = Array.isArray(definitions) ? definitions.find((t) => isObject7(t) && t.id === item.reference.id && t.saleStatus === "SALE_STARTED") : void 0;
|
|
3410
3526
|
if (!isObject7(live) || !samePrice(live.price, item)) return notCreated(CHANGED);
|
|
3411
|
-
|
|
3412
|
-
if (
|
|
3413
|
-
return
|
|
3527
|
+
const event = bodyObject(read2, "event");
|
|
3528
|
+
if (live.eventId !== selected.eventId || classifyForApple(availableTicketAttendanceOf(event, live), item.attendance.currency) !== "appleIap") return notCreated(ORDER_REFUSED);
|
|
3529
|
+
if (beforeCreate && !beforeCreate({ releaseAt: now() + reservationMinutes(event) * MINUTE_MS + RELEASE_MARGIN_MS })) return notCreated({ status: "refused", reason: "storageUnavailable" });
|
|
3530
|
+
return reserveTicket(item, bridge, now, afterCreate);
|
|
3531
|
+
}
|
|
3532
|
+
function reservationMinutes(event) {
|
|
3533
|
+
const registration = isObject7(event?.registration) ? event.registration : void 0;
|
|
3534
|
+
const minutes = isObject7(registration?.tickets) ? registration.tickets.reservationDurationInMinutes : void 0;
|
|
3535
|
+
return typeof minutes === "number" && minutes > 0 ? minutes : DEFAULT_RESERVATION_MINUTES;
|
|
3414
3536
|
}
|
|
3415
|
-
async function reserveTicket(item, bridge, now) {
|
|
3537
|
+
async function reserveTicket(item, bridge, now, afterCreate) {
|
|
3416
3538
|
const selected = item.attendance.ticket;
|
|
3417
3539
|
const held = await bridge.call("POST", "/events/v1/checkout/reservations", { eventId: selected.eventId, ticketQuantities: [{ ticketDefinitionId: item.reference.id, quantity: 1 }], ignoreLimits: false, allowHiddenTickets: false });
|
|
3418
3540
|
if (isRefusal(held)) return creationRefused(held);
|
|
3419
3541
|
const reservation = held.body;
|
|
3420
3542
|
if (!isObject7(reservation) || !isNonEmpty3(reservation.id) || !future(reservation.expires, now)) return ORDER_CLOSED;
|
|
3543
|
+
afterCreate?.({ verticalRef: { reservationId: reservation.id }, releaseAt: Date.parse(reservation.expires) + RELEASE_MARGIN_MS });
|
|
3421
3544
|
if (!heldAsSelected(reservation, item)) return CHANGED;
|
|
3422
3545
|
const placed = await bridge.call("POST", "/events/v1/checkout", { eventId: selected.eventId, reservationId: reservation.id, buyer: selected.buyer, ...selected.guests ? { guests: selected.guests } : {}, ...selected.buyerSubmission ? { buyerSubmission: selected.buyerSubmission } : {}, ...selected.guestSubmissions ? { guestSubmissions: selected.guestSubmissions } : {}, options: { silent: false, payInPerson: false, ignoreFormValidation: false, markAsPaid: false } });
|
|
3423
3546
|
if (isRefusal(placed)) return attemptRefused(placed);
|
|
@@ -664,8 +664,8 @@ var IAP_CATALOG_KINDS = ["onlineProgram", "storesProduct", "pricingPlan", "booki
|
|
|
664
664
|
|
|
665
665
|
// ../../core/sdk/iap/src/wix-payments-contract.ts
|
|
666
666
|
var HIMALAYA_SERVE_IAP_ROUTE = { prefix: "/himalaya-serve/v1/iap" };
|
|
667
|
-
var BOOKINGS_APPLE_SALES_ENABLED =
|
|
668
|
-
var EVENTS_APPLE_SALES_ENABLED =
|
|
667
|
+
var BOOKINGS_APPLE_SALES_ENABLED = true;
|
|
668
|
+
var EVENTS_APPLE_SALES_ENABLED = true;
|
|
669
669
|
var ATTENDANCE_SALE_RULE = { appProductId: (id) => id, productType: "CONSUMABLE" };
|
|
670
670
|
var STORES_ITEM_PAYMENT_ENABLED = false;
|
|
671
671
|
var STORES_APPLE_SALES_ENABLED = true;
|
|
@@ -1444,10 +1444,13 @@ function locationType(raw) {
|
|
|
1444
1444
|
return type === "CUSTOM" && addresses.every(describesNoPlace) ? ADDRESSLESS_CUSTOM : type;
|
|
1445
1445
|
}
|
|
1446
1446
|
function describesNoPlace(address) {
|
|
1447
|
-
const parts = ["country", "subdivision", "city", "postalCode", "
|
|
1447
|
+
const parts = ["country", "subdivision", "city", "postalCode", "addressLine2", "streetAddress", "location"];
|
|
1448
1448
|
if (parts.some((key) => address[key] !== void 0 && address[key] !== "")) return false;
|
|
1449
|
-
|
|
1450
|
-
|
|
1449
|
+
return [address.addressLine, address.formattedAddress].every((value) => {
|
|
1450
|
+
if (value !== void 0 && typeof value !== "string") return false;
|
|
1451
|
+
const description = value?.trim() ?? "";
|
|
1452
|
+
return description === "" || ONLINE_LABEL.test(description);
|
|
1453
|
+
});
|
|
1451
1454
|
}
|
|
1452
1455
|
var ONLINE_LABEL = /^(online|virtual)(\s+(class|classes|classroom|course|session|sessions|meeting|lesson|training|workshop|event))?$/i;
|
|
1453
1456
|
function ticketAttendanceOf(event, definition) {
|