@wix/himalaya-cli 0.1319.0 → 0.1321.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-config.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-module.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/biometrics/src/index.d.ts +11 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/catalog-pricing-contract.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/host-session.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/index.d.ts +13 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/mapping-source.d.ts +8 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments.d.ts +5 -4
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/tokens.d.ts +9 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +5 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-core.d.ts +3 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/checkout-source.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-contract.d.ts +83 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-core.d.ts +36 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce.d.ts +8 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/index.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/purchase-fields.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +1205 -71
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +125 -13
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +1 -1
- package/dist/cli.mjs +164 -56
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/capabilities.md +17 -0
- package/guides/designing-himi-screens.md +2 -0
- package/guides/getting-started.md +4 -2
- package/guides/himi-skill.md +4 -2
- package/guides/iap-pricing.md +33 -26
- package/guides/index.json +2 -1
- package/guides/qa-builds.md +34 -8
- package/guides/sdk-reference.json +17 -5
- package/guides/tokens.md +22 -1
- package/package.json +2 -2
- package/templates/branded-lite/dev/index.ts +41 -0
- package/templates/branded-lite/tier5-src/_shared/iap-worker.ts +21 -44
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +77 -47
- package/templates/branded-lite/tier5-src/himi-branded-lite-programs/index.ts +24 -38
- package/templates/brandy/README.md +5 -3
- package/templates/yoga-studio/dev/index.ts +41 -0
- package/templates/yoga-studio/tier5-src/_shared/iap-worker.ts +21 -44
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +77 -47
- package/templates/yoga-studio/tier5-src/himi-branded-lite-programs/index.ts +24 -38
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
// ../../stdlib/flows/iap-checkout/src/checkout-source.ts
|
|
2
|
-
function appleIapCheckoutEnabled() {
|
|
3
|
-
return false;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
1
|
// ../../core/sdk/dispatch/src/index.ts
|
|
7
2
|
function dispatch(handlerId, params, _options) {
|
|
8
3
|
const himalaya = globalThis.himalaya;
|
|
@@ -18,6 +13,31 @@ function dispatch(handlerId, params, _options) {
|
|
|
18
13
|
return himalaya.dispatch(handlerId, stringParams);
|
|
19
14
|
}
|
|
20
15
|
|
|
16
|
+
// ../../core/sdk/app-info/src/index.ts
|
|
17
|
+
var PLATFORMS = ["ios", "android", "macos", "web", "react-native"];
|
|
18
|
+
function str(v) {
|
|
19
|
+
return typeof v === "string" ? v.trim() : "";
|
|
20
|
+
}
|
|
21
|
+
async function get() {
|
|
22
|
+
const r = await dispatch("capability.app_info.get");
|
|
23
|
+
const platform = str(r?.platform);
|
|
24
|
+
const releaseId = str(r?.releaseId);
|
|
25
|
+
const serveBaseUrl = str(r?.serveBaseUrl);
|
|
26
|
+
return {
|
|
27
|
+
appId: str(r?.appId),
|
|
28
|
+
bundleId: str(r?.bundleId),
|
|
29
|
+
version: str(r?.version),
|
|
30
|
+
buildNumber: str(r?.buildNumber),
|
|
31
|
+
binaryVersion: str(r?.binaryVersion),
|
|
32
|
+
releaseId: releaseId || null,
|
|
33
|
+
releasePinned: r?.releasePinned === true,
|
|
34
|
+
// Trust the host's own answer; fall back to inferring from whether a serve origin is set.
|
|
35
|
+
environment: str(r?.environment) === "prod" ? "prod" : serveBaseUrl ? "prod" : "dev",
|
|
36
|
+
serveBaseUrl: serveBaseUrl || null,
|
|
37
|
+
platform: PLATFORMS.includes(platform) ? platform : "unknown"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
// ../../core/sdk/iap/src/delivery.ts
|
|
22
42
|
var MAX_AUTOMATIC_ATTEMPTS = 5;
|
|
23
43
|
var MAX_RETRY_DELAY_MS = 6e4;
|
|
@@ -30,7 +50,7 @@ function createPurchaseCoordinator(deps) {
|
|
|
30
50
|
let outcome = "idle";
|
|
31
51
|
let purchasing = false;
|
|
32
52
|
let signInPrompt = false;
|
|
33
|
-
let
|
|
53
|
+
let unavailable2 = null;
|
|
34
54
|
let pendingApproval = null;
|
|
35
55
|
let errorCode = null;
|
|
36
56
|
let errorFromReconcile = false;
|
|
@@ -66,7 +86,7 @@ function createPurchaseCoordinator(deps) {
|
|
|
66
86
|
if (disposed || !sessionMatches()) return { phase: "idle", errorCode: null, items: [], unfinishedCount: null, nextWakeAt: null };
|
|
67
87
|
const snapshot = [...items.values()].map((item) => ({ ...item.state }));
|
|
68
88
|
const due = snapshot.map((item) => item.nextAttemptAt).filter((at) => at !== null);
|
|
69
|
-
return { phase: currentPhase(), errorCode: errorCode ??
|
|
89
|
+
return { phase: currentPhase(), errorCode: errorCode ?? unavailable2?.code ?? null, items: snapshot, unfinishedCount, nextWakeAt: due.length > 0 ? Math.min(...due) : null };
|
|
70
90
|
}
|
|
71
91
|
function dispose() {
|
|
72
92
|
disposed = true;
|
|
@@ -78,7 +98,7 @@ function createPurchaseCoordinator(deps) {
|
|
|
78
98
|
setError(null, false);
|
|
79
99
|
outcome = "idle";
|
|
80
100
|
pendingApproval = null;
|
|
81
|
-
|
|
101
|
+
unavailable2 = null;
|
|
82
102
|
releaseSignIn();
|
|
83
103
|
if (session.kind !== "member") {
|
|
84
104
|
requireSignIn();
|
|
@@ -137,7 +157,7 @@ function createPurchaseCoordinator(deps) {
|
|
|
137
157
|
}
|
|
138
158
|
}
|
|
139
159
|
function clearReconcileProblem() {
|
|
140
|
-
if (
|
|
160
|
+
if (unavailable2?.from === "reconcile") unavailable2 = null;
|
|
141
161
|
if (errorFromReconcile) setError(null, false);
|
|
142
162
|
}
|
|
143
163
|
async function runRetry() {
|
|
@@ -304,7 +324,7 @@ function createPurchaseCoordinator(deps) {
|
|
|
304
324
|
outcome = "idle";
|
|
305
325
|
purchasing = false;
|
|
306
326
|
signInPrompt = false;
|
|
307
|
-
|
|
327
|
+
unavailable2 = null;
|
|
308
328
|
pendingApproval = null;
|
|
309
329
|
unfinishedCount = null;
|
|
310
330
|
setError(null, false);
|
|
@@ -362,8 +382,8 @@ function createPurchaseCoordinator(deps) {
|
|
|
362
382
|
}
|
|
363
383
|
function failStore(code, fromReconcile) {
|
|
364
384
|
setError(code, fromReconcile);
|
|
365
|
-
if (UNAVAILABLE_CODES.has(code) &&
|
|
366
|
-
|
|
385
|
+
if (UNAVAILABLE_CODES.has(code) && unavailable2?.from !== "purchase") {
|
|
386
|
+
unavailable2 = { from: fromReconcile ? "reconcile" : "purchase", code };
|
|
367
387
|
}
|
|
368
388
|
publish();
|
|
369
389
|
}
|
|
@@ -381,9 +401,9 @@ function createPurchaseCoordinator(deps) {
|
|
|
381
401
|
}
|
|
382
402
|
function currentPhase() {
|
|
383
403
|
if (purchasing) return "purchasing";
|
|
384
|
-
if (
|
|
404
|
+
if (unavailable2?.from === "purchase") return "unavailable";
|
|
385
405
|
if (signInPrompt) return "signInRequired";
|
|
386
|
-
if (
|
|
406
|
+
if (unavailable2?.from === "reconcile") return "unavailable";
|
|
387
407
|
return outcome;
|
|
388
408
|
}
|
|
389
409
|
function setError(code, fromReconcile) {
|
|
@@ -519,8 +539,8 @@ function createSerialQueue() {
|
|
|
519
539
|
return {
|
|
520
540
|
/** Callers joined onto a shared job all receive that job's result. */
|
|
521
541
|
run(name, job, { joinRunning = false }) {
|
|
522
|
-
const
|
|
523
|
-
if (
|
|
542
|
+
const shared2 = waiting.get(name) ?? (joinRunning ? running.get(name) : void 0);
|
|
543
|
+
if (shared2) return shared2;
|
|
524
544
|
const scheduled = tail.then(() => execute(name, scheduled, job));
|
|
525
545
|
waiting.set(name, scheduled);
|
|
526
546
|
tail = scheduled;
|
|
@@ -529,17 +549,741 @@ function createSerialQueue() {
|
|
|
529
549
|
};
|
|
530
550
|
}
|
|
531
551
|
|
|
552
|
+
// ../../core/sdk/iap/src/pricing.ts
|
|
553
|
+
function createPricingController(deps) {
|
|
554
|
+
let state = { revision: 0, scope: null, items: [] };
|
|
555
|
+
let lastInput;
|
|
556
|
+
let active;
|
|
557
|
+
let disposed = false;
|
|
558
|
+
function load(input) {
|
|
559
|
+
if (disposed) return Promise.resolve();
|
|
560
|
+
const captured = captureInput(input);
|
|
561
|
+
const key = JSON.stringify(captured);
|
|
562
|
+
if (active?.key === key) return active.promise;
|
|
563
|
+
lastInput = captured;
|
|
564
|
+
const revision = state.revision + 1;
|
|
565
|
+
let complete;
|
|
566
|
+
const promise = new Promise((resolve) => {
|
|
567
|
+
complete = resolve;
|
|
568
|
+
});
|
|
569
|
+
active = { key, promise };
|
|
570
|
+
publish({ revision, scope: captured.scope, items: captured.items.map((item) => ({ reference: item.reference, status: "loading" })) });
|
|
571
|
+
void run(captured, revision).finally(complete);
|
|
572
|
+
return promise;
|
|
573
|
+
}
|
|
574
|
+
async function run(input, revision) {
|
|
575
|
+
const current = () => !disposed && state.revision === revision;
|
|
576
|
+
if (!current()) return;
|
|
577
|
+
const items = await resolvePrices(input, deps, current);
|
|
578
|
+
if (!current()) return;
|
|
579
|
+
active = void 0;
|
|
580
|
+
publish({ revision, scope: input.scope, items });
|
|
581
|
+
}
|
|
582
|
+
function publish(next) {
|
|
583
|
+
state = next;
|
|
584
|
+
try {
|
|
585
|
+
deps.onState?.(getState());
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
function getState() {
|
|
590
|
+
return {
|
|
591
|
+
...state,
|
|
592
|
+
scope: state.scope ? { ...state.scope } : null,
|
|
593
|
+
items: state.items.map((item) => ({ ...item, reference: { ...item.reference } }))
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
function dispose() {
|
|
597
|
+
disposed = true;
|
|
598
|
+
active = void 0;
|
|
599
|
+
lastInput = void 0;
|
|
600
|
+
state = { revision: state.revision + 1, scope: null, items: [] };
|
|
601
|
+
}
|
|
602
|
+
return { load, refresh: () => lastInput ? load(lastInput) : Promise.resolve(), getState, dispose };
|
|
603
|
+
}
|
|
604
|
+
function captureInput(input) {
|
|
605
|
+
const scope = {
|
|
606
|
+
appId: input.scope.appId,
|
|
607
|
+
bundleId: input.scope.bundleId,
|
|
608
|
+
siteId: input.scope.siteId,
|
|
609
|
+
...input.scope.contextRevision === void 0 ? {} : { contextRevision: input.scope.contextRevision }
|
|
610
|
+
};
|
|
611
|
+
const items = /* @__PURE__ */ new Map();
|
|
612
|
+
for (const item of input.items) {
|
|
613
|
+
const reference = { kind: item.reference.kind, id: item.reference.id };
|
|
614
|
+
const key = JSON.stringify([reference.kind, reference.id]);
|
|
615
|
+
if (!items.has(key)) items.set(key, { reference, ...item.commerceDisplayPrice === void 0 ? {} : { commerceDisplayPrice: item.commerceDisplayPrice } });
|
|
616
|
+
}
|
|
617
|
+
return { scope, platform: input.platform, items: [...items.values()] };
|
|
618
|
+
}
|
|
619
|
+
async function resolvePrices(input, deps, current) {
|
|
620
|
+
if (input.items.length === 0) return [];
|
|
621
|
+
if (![input.scope.appId, input.scope.bundleId, input.scope.siteId].every(nonempty)) {
|
|
622
|
+
return input.items.map((item) => unavailable(item.reference, "invalidInput"));
|
|
623
|
+
}
|
|
624
|
+
const mappings = await resolveMappings(input, deps);
|
|
625
|
+
if (!current()) return [];
|
|
626
|
+
if (mappings === null) return input.items.map((item) => unavailable(item.reference, "mappingUnavailable"));
|
|
627
|
+
const routes = input.items.map((item) => resolveRoute(item, mappings, input.platform));
|
|
628
|
+
const ids = [...new Set(routes.flatMap((route) => route.status === "loading" ? [route.mapping.productId] : []))];
|
|
629
|
+
const products = ids.length ? await lookupProducts(ids, deps) : [];
|
|
630
|
+
return routes.map((route) => route.status === "loading" ? applePrice(route.mapping, products) : route);
|
|
631
|
+
}
|
|
632
|
+
async function resolveMappings(input, deps) {
|
|
633
|
+
try {
|
|
634
|
+
const references = input.items.filter((item) => nonempty(item.reference.kind) && nonempty(item.reference.id)).map((item) => ({ ...item.reference }));
|
|
635
|
+
if (!references.length) return [];
|
|
636
|
+
const result = await deps.mapping.resolve({ scope: { ...input.scope }, references });
|
|
637
|
+
return Array.isArray(result) ? result : [];
|
|
638
|
+
} catch {
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async function lookupProducts(ids, deps) {
|
|
643
|
+
try {
|
|
644
|
+
const products = await deps.getProducts(ids);
|
|
645
|
+
return Array.isArray(products) ? products : [];
|
|
646
|
+
} catch {
|
|
647
|
+
return [];
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function resolveRoute(item, mappings, platform) {
|
|
651
|
+
if (!nonempty(item.reference.kind) || !nonempty(item.reference.id)) return unavailable(item.reference, "invalidInput");
|
|
652
|
+
const matches = mappings.filter((value) => isObject2(value) && sameReference(value.reference, item.reference));
|
|
653
|
+
if (matches.length !== 1) return unavailable(item.reference, "mappingUnresolved");
|
|
654
|
+
const mapping = matches[0];
|
|
655
|
+
if (mapping.route === "regular") return regularPrice(item);
|
|
656
|
+
if (mapping.route !== "appleIap" || !nonempty(mapping.productId) || mapping.productId.includes(",") || !nonempty(mapping.mappingRevision)) {
|
|
657
|
+
return unavailable(item.reference, "mappingUnresolved");
|
|
658
|
+
}
|
|
659
|
+
if (platform !== "ios") return unavailable(item.reference, "unsupportedPlatform");
|
|
660
|
+
return { status: "loading", mapping: { reference: item.reference, route: "appleIap", productId: mapping.productId, mappingRevision: mapping.mappingRevision } };
|
|
661
|
+
}
|
|
662
|
+
function regularPrice(item) {
|
|
663
|
+
return nonempty(item.commerceDisplayPrice) ? { reference: item.reference, status: "ready", source: "regular", displayPrice: item.commerceDisplayPrice } : unavailable(item.reference, "commercePriceUnavailable");
|
|
664
|
+
}
|
|
665
|
+
function applePrice(mapping, products) {
|
|
666
|
+
const matches = products.filter((value) => isObject2(value) && value.id === mapping.productId);
|
|
667
|
+
const product = matches[0];
|
|
668
|
+
if (matches.length !== 1 || !nonempty(product?.displayPrice)) return unavailable(mapping.reference, "priceUnavailable");
|
|
669
|
+
if (product?.type !== "nonConsumable") return unavailable(mapping.reference, "unsupportedProductType");
|
|
670
|
+
return {
|
|
671
|
+
reference: mapping.reference,
|
|
672
|
+
status: "ready",
|
|
673
|
+
source: "appleIap",
|
|
674
|
+
productId: mapping.productId,
|
|
675
|
+
mappingRevision: mapping.mappingRevision,
|
|
676
|
+
displayPrice: product.displayPrice
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function unavailable(reference, reason) {
|
|
680
|
+
return { reference, status: "unavailable", reason, retryable: !["invalidInput", "unsupportedPlatform", "unsupportedProductType", "commercePriceUnavailable"].includes(reason) };
|
|
681
|
+
}
|
|
682
|
+
var isObject2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
683
|
+
var nonempty = (value) => typeof value === "string" && value.trim().length > 0;
|
|
684
|
+
var sameReference = (value, reference) => isObject2(value) && value.kind === reference.kind && value.id === reference.id;
|
|
685
|
+
|
|
686
|
+
// ../../core/sdk/iap/src/wix-payments-contract.ts
|
|
687
|
+
var HIMALAYA_SERVE_IAP_ROUTE = { prefix: "/himalaya-serve/v1/iap" };
|
|
688
|
+
var APPLE_SALE_RULES = {
|
|
689
|
+
onlineProgram: { appProductId: (id) => id, productType: "NON_CONSUMABLE" }
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
// ../../core/sdk/iap/src/mapping-source.ts
|
|
693
|
+
function iapMappingSource() {
|
|
694
|
+
return createWixIapMappingSource({ binding: sharedHostAppBindingSource(), call: hostWixCall });
|
|
695
|
+
}
|
|
696
|
+
function createWixIapMappingSource(deps) {
|
|
697
|
+
return {
|
|
698
|
+
// Only a binding the host actually returned: a read that failed is re-asked on the next load.
|
|
699
|
+
active: async () => await deps.binding.current() !== null,
|
|
700
|
+
mapping: {
|
|
701
|
+
resolve: async ({ scope, references }) => {
|
|
702
|
+
const binding = await deps.binding.current();
|
|
703
|
+
if (!binding) return references.map((reference) => ({ reference, route: "regular" }));
|
|
704
|
+
if (scope.siteId && !sameId(scope.siteId, binding.siteId)) return references.map((reference) => ({ reference, route: "unavailable" }));
|
|
705
|
+
const asked = [...new Set(references.flatMap((reference) => appProductIdOf(reference) ?? []))];
|
|
706
|
+
const mapped = await resolveAll(deps.call, binding, asked);
|
|
707
|
+
return references.map((reference) => decide(reference, binding, mapped));
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function appProductIdOf(reference) {
|
|
713
|
+
return reference.id ? APPLE_SALE_RULES[reference.kind]?.appProductId(reference.id) : void 0;
|
|
714
|
+
}
|
|
715
|
+
var PATH = `${HIMALAYA_SERVE_IAP_ROUTE.prefix}/mappings`;
|
|
716
|
+
var BATCH = 100;
|
|
717
|
+
async function resolveAll(call, binding, ids) {
|
|
718
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
719
|
+
const wanted = new Set(ids);
|
|
720
|
+
for (let at = 0; at < ids.length; at += BATCH) {
|
|
721
|
+
const batch = ids.slice(at, at + BATCH);
|
|
722
|
+
const reply = await call("POST", PATH, { appId: binding.purchasesAppId, appProductIds: batch }, { "wix-site-id": binding.siteId });
|
|
723
|
+
for (const [id, mapping] of decodeMappings(reply)) if (wanted.has(id)) mapped.set(id, mapping);
|
|
724
|
+
}
|
|
725
|
+
return mapped;
|
|
726
|
+
}
|
|
727
|
+
function decodeMappings(reply) {
|
|
728
|
+
const list = reply?.mappings;
|
|
729
|
+
if (!Array.isArray(list)) throw new Error("the mapping route answered without a mappings list");
|
|
730
|
+
return list.map((raw) => {
|
|
731
|
+
const m = raw;
|
|
732
|
+
if (typeof m?.appProductId !== "string" || typeof m.storeProductId !== "string" || !m.storeProductId) {
|
|
733
|
+
throw new Error("the mapping route answered a mapping without its ids");
|
|
734
|
+
}
|
|
735
|
+
return [m.appProductId, { storeProductId: m.storeProductId, type: String(m.type ?? ""), active: m.active === true }];
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
function decide(reference, binding, mapped) {
|
|
739
|
+
const id = appProductIdOf(reference);
|
|
740
|
+
const mapping = id ? mapped.get(id) : void 0;
|
|
741
|
+
if (!mapping) return { reference, route: "regular" };
|
|
742
|
+
if (!mapping.active || mapping.type !== APPLE_SALE_RULES[reference.kind]?.productType) return { reference, route: "unavailable" };
|
|
743
|
+
return { reference, route: "appleIap", productId: mapping.storeProductId, mappingRevision: `${binding.purchasesAppId}:${mapping.storeProductId}` };
|
|
744
|
+
}
|
|
745
|
+
function sameId(a, b) {
|
|
746
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
747
|
+
}
|
|
748
|
+
function hostWixCall(method, path, body, headers) {
|
|
749
|
+
const bridge = globalThis.himalaya?.wixApi;
|
|
750
|
+
if (!bridge) return Promise.reject(new Error("the host did not install the wixApi bridge"));
|
|
751
|
+
return bridge.call(method, path, body, headers);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// ../../core/sdk/iap/src/catalog-pricing-core.ts
|
|
755
|
+
var POLL_ID = "iapCatalogPricing";
|
|
756
|
+
var POLL_INTERVAL_MS = 6e4;
|
|
757
|
+
function createIapCatalogPricingWith(deps) {
|
|
758
|
+
return deps.source ? enabledPricing(deps.source, deps) : disabledPricing();
|
|
759
|
+
}
|
|
760
|
+
function disabledPricing() {
|
|
761
|
+
return {
|
|
762
|
+
enabled: false,
|
|
763
|
+
load: () => Promise.resolve(),
|
|
764
|
+
refresh: () => Promise.resolve(),
|
|
765
|
+
view: disabledView,
|
|
766
|
+
checkoutGuard: (reference) => decisionOf(disabledView(reference)),
|
|
767
|
+
continueCheckoutGuard: (reference) => decisionOf(disabledView(reference)),
|
|
768
|
+
appleProduct: () => null,
|
|
769
|
+
pollDirective: () => void 0,
|
|
770
|
+
dispose: () => {
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
function enabledPricing(source, deps) {
|
|
775
|
+
let controller;
|
|
776
|
+
let disposed = false;
|
|
777
|
+
const settled = /* @__PURE__ */ new Map();
|
|
778
|
+
let settledScope = "";
|
|
779
|
+
const rememberSettled = (state) => {
|
|
780
|
+
const scopeKey = JSON.stringify(state.scope);
|
|
781
|
+
if (scopeKey !== settledScope) {
|
|
782
|
+
settled.clear();
|
|
783
|
+
settledScope = scopeKey;
|
|
784
|
+
}
|
|
785
|
+
for (const item of state.items) {
|
|
786
|
+
const answered = viewOf(item.reference, item);
|
|
787
|
+
if (!unanswered(answered)) settled.set(referenceKey(item.reference), answered);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
let selling = "active";
|
|
791
|
+
let lookupRevision = 0;
|
|
792
|
+
let answeredRoutes;
|
|
793
|
+
const mapping = {
|
|
794
|
+
resolve: async (request) => {
|
|
795
|
+
const asked = lookupRevision;
|
|
796
|
+
const answer = await source.mapping.resolve(request);
|
|
797
|
+
if (asked === lookupRevision) answeredRoutes = routesAnswered(answer);
|
|
798
|
+
return answer;
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
const trackLookup = (state) => {
|
|
802
|
+
if (state.revision !== lookupRevision) {
|
|
803
|
+
lookupRevision = state.revision;
|
|
804
|
+
answeredRoutes = void 0;
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
const ensureController = () => controller ?? (controller = createPricingController({
|
|
808
|
+
mapping,
|
|
809
|
+
getProducts: deps.getProducts,
|
|
810
|
+
onState: (state) => {
|
|
811
|
+
trackLookup(state);
|
|
812
|
+
rememberSettled(state);
|
|
813
|
+
deps.onChange?.();
|
|
814
|
+
}
|
|
815
|
+
}));
|
|
816
|
+
const view = (reference) => disposed ? blockedView(reference, "unavailable") : selling === "inactive" ? disabledView(reference) : selling === "unknown" ? sellingUnknownView(reference) : viewOf(reference, controller && itemFor(controller.getState().items, reference));
|
|
817
|
+
const load = async (input) => {
|
|
818
|
+
if (disposed) return;
|
|
819
|
+
selling = source.active ? await source.active().then((active) => active ? "active" : "inactive", () => "unknown") : "active";
|
|
820
|
+
if (selling !== "active") {
|
|
821
|
+
deps.onChange?.();
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
await ensureController().load(pricingInput(input, source));
|
|
825
|
+
};
|
|
826
|
+
const continueCheckoutGuard = (reference) => {
|
|
827
|
+
const current = view(reference);
|
|
828
|
+
if (!unanswered(current) || selling !== "active") return decisionOf(current);
|
|
829
|
+
if (answeredRoutes) return routeDecision(answeredRoutes.get(referenceKey(reference)) ?? "unavailable");
|
|
830
|
+
return decisionOf(settled.get(referenceKey(reference)) ?? current);
|
|
831
|
+
};
|
|
832
|
+
return {
|
|
833
|
+
enabled: true,
|
|
834
|
+
load,
|
|
835
|
+
refresh: () => controller?.refresh() ?? Promise.resolve(),
|
|
836
|
+
view,
|
|
837
|
+
checkoutGuard: (reference) => decisionOf(view(reference)),
|
|
838
|
+
continueCheckoutGuard,
|
|
839
|
+
appleProduct: (reference) => disposed || selling !== "active" ? null : appleProductOf(controller && itemFor(controller.getState().items, reference)),
|
|
840
|
+
pollDirective: (action2) => ({ id: POLL_ID, action: action2, intervalMs: POLL_INTERVAL_MS, immediate: true }),
|
|
841
|
+
dispose: () => {
|
|
842
|
+
disposed = true;
|
|
843
|
+
settled.clear();
|
|
844
|
+
controller?.dispose();
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
function pricingInput(input, source) {
|
|
849
|
+
return { scope: pricingScope(input.scope, source.siteId), platform: input.platform, items: input.items };
|
|
850
|
+
}
|
|
851
|
+
function pricingScope(scope, boundSiteId) {
|
|
852
|
+
return {
|
|
853
|
+
appId: scope.appId,
|
|
854
|
+
bundleId: scope.bundleId,
|
|
855
|
+
siteId: siteIdFor(scope.siteId, boundSiteId),
|
|
856
|
+
...scope.contextRevision === void 0 ? {} : { contextRevision: scope.contextRevision }
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
function siteIdFor(callerSiteId, boundSiteId) {
|
|
860
|
+
if (callerSiteId && boundSiteId && callerSiteId !== boundSiteId) return "";
|
|
861
|
+
return callerSiteId || boundSiteId || "";
|
|
862
|
+
}
|
|
863
|
+
var referenceKey = (reference) => JSON.stringify([reference.kind, reference.id]);
|
|
864
|
+
function routesAnswered(answer) {
|
|
865
|
+
const routes = /* @__PURE__ */ new Map();
|
|
866
|
+
for (const entry of Array.isArray(answer) ? answer : []) {
|
|
867
|
+
const reference = entry?.reference;
|
|
868
|
+
if (typeof reference?.kind !== "string" || typeof reference.id !== "string") continue;
|
|
869
|
+
const key = referenceKey(reference);
|
|
870
|
+
const route = entry.route;
|
|
871
|
+
routes.set(key, routes.has(key) ? "unavailable" : route === "regular" || route === "appleIap" ? route : "unavailable");
|
|
872
|
+
}
|
|
873
|
+
return routes;
|
|
874
|
+
}
|
|
875
|
+
function routeDecision(route) {
|
|
876
|
+
return { allowed: route === "regular", route };
|
|
877
|
+
}
|
|
878
|
+
function unanswered(view) {
|
|
879
|
+
return view.route === "resolving" || view.reason === "mappingUnavailable";
|
|
880
|
+
}
|
|
881
|
+
function itemFor(items, reference) {
|
|
882
|
+
return items.find((item) => item.reference.kind === reference.kind && item.reference.id === reference.id);
|
|
883
|
+
}
|
|
884
|
+
function appleProductOf(item) {
|
|
885
|
+
if (item?.status !== "ready" || item.source !== "appleIap") return null;
|
|
886
|
+
return { productId: item.productId, mappingRevision: item.mappingRevision };
|
|
887
|
+
}
|
|
888
|
+
function viewOf(reference, item) {
|
|
889
|
+
if (!item || item.status === "loading") return blockedView(reference, "resolving");
|
|
890
|
+
if (item.status === "ready") return readyView(reference, item);
|
|
891
|
+
return unavailableView(reference, item);
|
|
892
|
+
}
|
|
893
|
+
function readyView(reference, item) {
|
|
894
|
+
return item.source === "appleIap" ? { ...blockedView(reference, "appleIap"), displayPrice: item.displayPrice } : { ...regularView(reference), displayPrice: item.displayPrice };
|
|
895
|
+
}
|
|
896
|
+
function unavailableView(reference, item) {
|
|
897
|
+
if (item.reason === "commercePriceUnavailable") return regularView(reference);
|
|
898
|
+
return { ...blockedView(reference, "unavailable"), reason: item.reason, retryable: item.retryable };
|
|
899
|
+
}
|
|
900
|
+
function blockedView(reference, route) {
|
|
901
|
+
return { reference: { kind: reference.kind, id: reference.id }, route, displayPrice: "", retryable: false, canStartRegularCheckout: false, purchasable: false };
|
|
902
|
+
}
|
|
903
|
+
function regularView(reference) {
|
|
904
|
+
return { ...blockedView(reference, "regular"), canStartRegularCheckout: true };
|
|
905
|
+
}
|
|
906
|
+
function sellingUnknownView(reference) {
|
|
907
|
+
return { ...blockedView(reference, "unavailable"), reason: "mappingUnavailable", retryable: true };
|
|
908
|
+
}
|
|
909
|
+
function disabledView(reference) {
|
|
910
|
+
return { ...blockedView(reference, "disabled"), canStartRegularCheckout: true };
|
|
911
|
+
}
|
|
912
|
+
function decisionOf(view) {
|
|
913
|
+
return { allowed: view.canStartRegularCheckout, route: view.route };
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// ../../core/sdk/iap/src/catalog-pricing.ts
|
|
917
|
+
function createIapCatalogPricing(options = {}) {
|
|
918
|
+
return createIapCatalogPricingWith({ source: iapMappingSource(), getProducts, onChange: options.onChange });
|
|
919
|
+
}
|
|
920
|
+
|
|
532
921
|
// ../../core/sdk/iap/src/host-session.ts
|
|
922
|
+
var SIGNED_OUT = {
|
|
923
|
+
generation: 0,
|
|
924
|
+
kind: "signedOut",
|
|
925
|
+
memberId: null,
|
|
926
|
+
siteId: null,
|
|
927
|
+
appId: null,
|
|
928
|
+
ready: false,
|
|
929
|
+
epoch: 0
|
|
930
|
+
};
|
|
931
|
+
var KINDS = /* @__PURE__ */ new Set(["member", "visitor", "owner", "signedOut"]);
|
|
932
|
+
function createHostSession(source) {
|
|
933
|
+
let seen = -1;
|
|
934
|
+
let latest = SIGNED_OUT;
|
|
935
|
+
const byGeneration = /* @__PURE__ */ new Map();
|
|
936
|
+
function pull() {
|
|
937
|
+
const snap = parseSession(source.current());
|
|
938
|
+
if (snap.generation < seen) return latest;
|
|
939
|
+
seen = snap.generation;
|
|
940
|
+
latest = snap;
|
|
941
|
+
const expectation = expectationOf(snap);
|
|
942
|
+
if (expectation && !byGeneration.has(snap.generation)) byGeneration.set(snap.generation, expectation);
|
|
943
|
+
return snap;
|
|
944
|
+
}
|
|
945
|
+
return {
|
|
946
|
+
identityBound: source.identityBound,
|
|
947
|
+
current() {
|
|
948
|
+
const snap = pull();
|
|
949
|
+
return { generation: snap.generation, kind: snap.kind };
|
|
950
|
+
},
|
|
951
|
+
identity(session) {
|
|
952
|
+
pull();
|
|
953
|
+
return byGeneration.get(session.generation) ?? null;
|
|
954
|
+
},
|
|
955
|
+
site() {
|
|
956
|
+
const snap = pull();
|
|
957
|
+
return snap.ready ? snap.siteId : null;
|
|
958
|
+
},
|
|
959
|
+
subscribe(listener) {
|
|
960
|
+
return source.subscribe(() => {
|
|
961
|
+
const before = seen;
|
|
962
|
+
pull();
|
|
963
|
+
if (latest.generation >= before) listener();
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
function hostSessionFromGlobal() {
|
|
969
|
+
const api = wixApiGlobal();
|
|
970
|
+
const session = api?.session;
|
|
971
|
+
if (!session || typeof session.current !== "function" || typeof session.subscribe !== "function") {
|
|
972
|
+
return createHostSession({ identityBound: false, current: () => SIGNED_OUT, subscribe: () => () => {
|
|
973
|
+
} });
|
|
974
|
+
}
|
|
975
|
+
return createHostSession({
|
|
976
|
+
identityBound: api?.identityBound === true,
|
|
977
|
+
current: () => session.current(),
|
|
978
|
+
subscribe: (listener) => session.subscribe(listener)
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
function memberIdentityOf(source) {
|
|
982
|
+
return { memberId: (session) => Promise.resolve(source.identity(session)?.memberId ?? null) };
|
|
983
|
+
}
|
|
533
984
|
function readIdentityBound() {
|
|
534
985
|
return wixApiGlobal()?.identityBound === true;
|
|
535
986
|
}
|
|
987
|
+
function expectationOf(snap) {
|
|
988
|
+
if (!snap.ready || snap.kind !== "member" || !snap.memberId || !snap.siteId || !snap.appId) return null;
|
|
989
|
+
return { generation: snap.generation, kind: "member", memberId: snap.memberId, siteId: snap.siteId, appId: snap.appId };
|
|
990
|
+
}
|
|
991
|
+
function parseSession(raw) {
|
|
992
|
+
if (raw === null || typeof raw !== "object") return SIGNED_OUT;
|
|
993
|
+
const value = raw;
|
|
994
|
+
const kind = value.kind;
|
|
995
|
+
if (typeof value.generation !== "number" || !Number.isSafeInteger(value.generation)) return SIGNED_OUT;
|
|
996
|
+
if (typeof kind !== "string" || !KINDS.has(kind)) return SIGNED_OUT;
|
|
997
|
+
return {
|
|
998
|
+
generation: value.generation,
|
|
999
|
+
kind,
|
|
1000
|
+
memberId: typeof value.memberId === "string" && value.memberId.length > 0 ? value.memberId : null,
|
|
1001
|
+
siteId: typeof value.siteId === "string" && value.siteId.length > 0 ? value.siteId : null,
|
|
1002
|
+
appId: typeof value.appId === "string" && value.appId.length > 0 ? value.appId : null,
|
|
1003
|
+
ready: value.ready === true,
|
|
1004
|
+
epoch: typeof value.epoch === "number" ? value.epoch : 0
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
536
1007
|
function wixApiGlobal() {
|
|
537
1008
|
return globalThis.himalaya?.wixApi;
|
|
538
1009
|
}
|
|
539
1010
|
|
|
1011
|
+
// ../../core/sdk/iap/src/wix-payments-wire.ts
|
|
1012
|
+
function startPaymentCall(scope, wixTransactionId) {
|
|
1013
|
+
return post(scope, "/payments/start", { appId: scope.binding.purchasesAppId, wixTransactionId });
|
|
1014
|
+
}
|
|
1015
|
+
function completePaymentCall(scope, signedTransaction) {
|
|
1016
|
+
return post(scope, "/payments/complete", { appId: scope.binding.purchasesAppId, apple: { signedTransaction } });
|
|
1017
|
+
}
|
|
1018
|
+
function paymentCall(scope, paymentId) {
|
|
1019
|
+
return get2(scope, `/payments/${encodeURIComponent(paymentId)}`);
|
|
1020
|
+
}
|
|
1021
|
+
function isRoutePrefix(prefix) {
|
|
1022
|
+
return /^\/[A-Za-z0-9._~\-/]*[A-Za-z0-9._~-]$/.test(prefix);
|
|
1023
|
+
}
|
|
1024
|
+
function decodeStarted(raw, expected) {
|
|
1025
|
+
if (!isObject3(raw) || !isStoreProductId(raw.storeProductId) || !isUUID(raw.appAccountToken)) return null;
|
|
1026
|
+
const payment = decodePayment(raw.payment, expected);
|
|
1027
|
+
return payment && { payment, storeProductId: raw.storeProductId, appAccountToken: raw.appAccountToken };
|
|
1028
|
+
}
|
|
1029
|
+
function decodePaymentAnswer(raw, expected) {
|
|
1030
|
+
return isObject3(raw) ? decodePayment(raw.payment, expected) : null;
|
|
1031
|
+
}
|
|
1032
|
+
function decodePayment(raw, expected) {
|
|
1033
|
+
if (!isObject3(raw) || !hasPaymentIds(raw) || !echoes(raw, expected) || !hasValidOptionals(raw)) return null;
|
|
1034
|
+
const status = ownValue(STATUSES, raw.status);
|
|
1035
|
+
return status ? toPayment(raw, status) : null;
|
|
1036
|
+
}
|
|
1037
|
+
function hasPaymentIds(raw) {
|
|
1038
|
+
return isUUID(raw.id) && isUUID(raw.appId) && isUUID(raw.memberId) && isUUID(raw.wixTransactionId);
|
|
1039
|
+
}
|
|
1040
|
+
function echoes(raw, expected) {
|
|
1041
|
+
return sameUUID(raw.appId, expected.appId) && (expected.memberId === null || sameUUID(raw.memberId, expected.memberId)) && (expected.paymentId === void 0 || sameUUID(raw.id, expected.paymentId)) && (expected.wixTransactionId === void 0 || sameUUID(raw.wixTransactionId, expected.wixTransactionId));
|
|
1042
|
+
}
|
|
1043
|
+
function hasValidOptionals(raw) {
|
|
1044
|
+
return (raw.appProductId === void 0 || isStoreProductId(raw.appProductId)) && (raw.purchaseTransactionId === void 0 || isUUID(raw.purchaseTransactionId)) && TIMESTAMPS.every((field) => raw[field] === void 0 || isTimestamp(raw[field]));
|
|
1045
|
+
}
|
|
1046
|
+
function toPayment(raw, status) {
|
|
1047
|
+
const optional = {
|
|
1048
|
+
appProductId: raw.appProductId,
|
|
1049
|
+
cancelReason: ownValue(CANCEL_REASONS, raw.cancelReason),
|
|
1050
|
+
purchaseTransactionId: raw.purchaseTransactionId,
|
|
1051
|
+
expiresDate: raw.expiresDate,
|
|
1052
|
+
approvedDate: raw.approvedDate,
|
|
1053
|
+
canceledDate: raw.canceledDate,
|
|
1054
|
+
refundedDate: raw.refundedDate
|
|
1055
|
+
};
|
|
1056
|
+
const ids = { paymentId: raw.id, appId: raw.appId, memberId: raw.memberId, wixTransactionId: raw.wixTransactionId };
|
|
1057
|
+
return { ...ids, status, ...withoutUndefined(optional) };
|
|
1058
|
+
}
|
|
1059
|
+
function classifyFailure(error, operation, codes) {
|
|
1060
|
+
const message = messageOf(error);
|
|
1061
|
+
if (BRIDGE_REFUSAL.test(message)) return failure(operation, "notEnabled");
|
|
1062
|
+
if (PRINCIPAL_CHANGED.test(message)) return failure(operation, "sessionChanged");
|
|
1063
|
+
const http = /^HTTP (\d{3})(?: \[([^\]]+)\])?:/.exec(message);
|
|
1064
|
+
if (!http) return failure(operation, "unavailable");
|
|
1065
|
+
return classifyHttp({ operation, codes, httpStatus: Number(http[1]), code: http[2] ?? "" });
|
|
1066
|
+
}
|
|
1067
|
+
function failure(operation, kind) {
|
|
1068
|
+
return { status: "failed", operation, kind };
|
|
1069
|
+
}
|
|
1070
|
+
function classifyHttp(refusal) {
|
|
1071
|
+
const { operation, codes, httpStatus, code } = refusal;
|
|
1072
|
+
if (code === "PRINCIPAL_CHANGED") return failure(operation, "sessionChanged");
|
|
1073
|
+
if (isOneOf(codes, code)) return { status: "failed", operation, kind: "application", code, httpStatus };
|
|
1074
|
+
return { status: "failed", operation, kind: kindForStatus(httpStatus, code), httpStatus };
|
|
1075
|
+
}
|
|
1076
|
+
function kindForStatus(httpStatus, code) {
|
|
1077
|
+
if (code === "UNAVAILABLE" || httpStatus === 408 || httpStatus === 429 || httpStatus >= 500) return "unavailable";
|
|
1078
|
+
if (httpStatus === 401 || code === "UNAUTHENTICATED") return "authRequired";
|
|
1079
|
+
if (httpStatus === 403 || code === "PERMISSION_DENIED") return "notPermitted";
|
|
1080
|
+
return "unrecognized";
|
|
1081
|
+
}
|
|
1082
|
+
function post(scope, route, body) {
|
|
1083
|
+
return { method: "POST", path: `${scope.prefix}${route}`, body, headers: siteHeaders(scope.binding) };
|
|
1084
|
+
}
|
|
1085
|
+
function get2(scope, route) {
|
|
1086
|
+
return { method: "GET", path: `${scope.prefix}${route}`, headers: siteHeaders(scope.binding) };
|
|
1087
|
+
}
|
|
1088
|
+
function siteHeaders(binding) {
|
|
1089
|
+
return { "wix-site-id": binding.siteId };
|
|
1090
|
+
}
|
|
1091
|
+
function messageOf(error) {
|
|
1092
|
+
const message = error?.message;
|
|
1093
|
+
return typeof message === "string" ? message : "";
|
|
1094
|
+
}
|
|
1095
|
+
function withoutUndefined(value) {
|
|
1096
|
+
const kept = {};
|
|
1097
|
+
for (const key of Object.keys(value)) {
|
|
1098
|
+
if (value[key] !== void 0) kept[key] = value[key];
|
|
1099
|
+
}
|
|
1100
|
+
return kept;
|
|
1101
|
+
}
|
|
1102
|
+
function isOneOf(codes, code) {
|
|
1103
|
+
return codes.includes(code);
|
|
1104
|
+
}
|
|
1105
|
+
function ownValue(table, key) {
|
|
1106
|
+
return typeof key === "string" && Object.prototype.hasOwnProperty.call(table, key) ? table[key] : void 0;
|
|
1107
|
+
}
|
|
1108
|
+
function isObject3(value) {
|
|
1109
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1110
|
+
}
|
|
1111
|
+
function isUUID(value) {
|
|
1112
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
1113
|
+
}
|
|
1114
|
+
function sameUUID(value, expected) {
|
|
1115
|
+
return isUUID(value) && value.toLowerCase() === expected.toLowerCase();
|
|
1116
|
+
}
|
|
1117
|
+
function isStoreProductId(value) {
|
|
1118
|
+
return typeof value === "string" && value.length > 0 && value.length <= 255;
|
|
1119
|
+
}
|
|
1120
|
+
function isTimestamp(value) {
|
|
1121
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
1122
|
+
}
|
|
1123
|
+
var STATUSES = {
|
|
1124
|
+
PENDING: "pending",
|
|
1125
|
+
APPROVING: "approving",
|
|
1126
|
+
APPROVED: "approved",
|
|
1127
|
+
CANCELING: "canceling",
|
|
1128
|
+
CANCELED: "canceled",
|
|
1129
|
+
REFUNDING: "refunding",
|
|
1130
|
+
REFUNDED: "refunded"
|
|
1131
|
+
};
|
|
1132
|
+
var CANCEL_REASONS = { EXPIRED: "expired", REJECTED: "rejected" };
|
|
1133
|
+
var TIMESTAMPS = ["createdDate", "updatedDate", "expiresDate", "approvedDate", "canceledDate", "refundedDate"];
|
|
1134
|
+
var BRIDGE_REFUSAL = /^(wixApi not enabled|capability wix_api not allowed)\b|^NotInstalled\(\)$/;
|
|
1135
|
+
var PRINCIPAL_CHANGED = /^PRINCIPAL_CHANGED\b/;
|
|
1136
|
+
|
|
1137
|
+
// ../../core/sdk/iap/src/wix-payments.ts
|
|
1138
|
+
function createWixIapClient(deps) {
|
|
1139
|
+
function startPayment(input) {
|
|
1140
|
+
if (!isUUID(input.wixTransactionId)) return Promise.resolve(failure("startPayment", "invalidArgument"));
|
|
1141
|
+
return run({
|
|
1142
|
+
operation: "startPayment",
|
|
1143
|
+
codes: START_PAYMENT_CODES,
|
|
1144
|
+
request: (scope) => startPaymentCall(scope, input.wixTransactionId),
|
|
1145
|
+
decode: (raw, scope) => {
|
|
1146
|
+
const started = decodeStarted(raw, { ...expectationOf2(scope), wixTransactionId: input.wixTransactionId });
|
|
1147
|
+
return started && { status: "started", ...started };
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
function completePayment(transaction) {
|
|
1152
|
+
const refusal = refuseProof(transaction);
|
|
1153
|
+
if (refusal) return Promise.resolve(refusal);
|
|
1154
|
+
return run({
|
|
1155
|
+
operation: "completePayment",
|
|
1156
|
+
codes: COMPLETE_PAYMENT_CODES,
|
|
1157
|
+
request: (scope) => completePaymentCall(scope, transaction.signedTransaction),
|
|
1158
|
+
decode: (raw, scope) => {
|
|
1159
|
+
const payment = decodePaymentAnswer(raw, expectationOf2(scope));
|
|
1160
|
+
return payment && { status: "matched", payment };
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
function getPayment(input) {
|
|
1165
|
+
if (!isUUID(input.paymentId)) return Promise.resolve(failure("getPayment", "invalidArgument"));
|
|
1166
|
+
return run({
|
|
1167
|
+
operation: "getPayment",
|
|
1168
|
+
codes: GET_PAYMENT_CODES,
|
|
1169
|
+
request: (scope) => paymentCall(scope, input.paymentId),
|
|
1170
|
+
decode: (raw, scope) => {
|
|
1171
|
+
const payment = decodePaymentAnswer(raw, { ...expectationOf2(scope), paymentId: input.paymentId });
|
|
1172
|
+
return payment && { status: "found", payment };
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
async function run(spec) {
|
|
1177
|
+
const scope = await resolveScope(deps.session.current(), spec.operation);
|
|
1178
|
+
if ("failure" in scope) return scope.failure;
|
|
1179
|
+
const sent = await send(scope, spec);
|
|
1180
|
+
if ("failure" in sent) return sent.failure;
|
|
1181
|
+
return spec.decode(sent.answer, scope) ?? failure(spec.operation, "invalidResponse");
|
|
1182
|
+
}
|
|
1183
|
+
async function resolveScope(session, operation) {
|
|
1184
|
+
if (session.kind !== "member") return refused(operation, "authRequired");
|
|
1185
|
+
if (!isRoutePrefix(deps.route.prefix)) return refused(operation, "notProvisioned");
|
|
1186
|
+
const binding = await read(() => deps.binding.current(), operation);
|
|
1187
|
+
if ("failure" in binding) return binding;
|
|
1188
|
+
if (!binding.value || !isBindingFor(binding.value, deps.host)) return refused(operation, "notProvisioned");
|
|
1189
|
+
const member = await expectedMember(session, operation);
|
|
1190
|
+
if ("failure" in member) return member;
|
|
1191
|
+
return { session, binding: binding.value, prefix: deps.route.prefix, memberId: member.memberId };
|
|
1192
|
+
}
|
|
1193
|
+
async function expectedMember(session, operation) {
|
|
1194
|
+
const identity = deps.identity;
|
|
1195
|
+
if (!identity) return { memberId: null };
|
|
1196
|
+
const memberId = await read(() => identity.memberId(session), operation);
|
|
1197
|
+
if ("failure" in memberId) return memberId;
|
|
1198
|
+
return memberId.value ? { memberId: memberId.value } : refused(operation, "authRequired");
|
|
1199
|
+
}
|
|
1200
|
+
async function send(scope, spec) {
|
|
1201
|
+
const transport = deps.transport ?? bridgeTransport();
|
|
1202
|
+
if (!transport) return refused(spec.operation, "notEnabled");
|
|
1203
|
+
if (!isCurrent(scope.session)) return refused(spec.operation, "sessionChanged");
|
|
1204
|
+
const expectation = boundExpectation2(scope.session, deps.transport == null);
|
|
1205
|
+
if (expectation === "refuse") return refused(spec.operation, "notEnabled");
|
|
1206
|
+
const outcome = await attempt(transport, spec.request(scope), spec, expectation);
|
|
1207
|
+
return isCurrent(scope.session) ? outcome : refused(spec.operation, "sessionChanged");
|
|
1208
|
+
}
|
|
1209
|
+
function boundExpectation2(session, liveHost) {
|
|
1210
|
+
const source = deps.session;
|
|
1211
|
+
if (liveHost && (source.identityBound !== true || !readIdentityBound())) return "refuse";
|
|
1212
|
+
if (typeof source.identity !== "function") return liveHost ? "refuse" : void 0;
|
|
1213
|
+
return source.identity(session) ?? "refuse";
|
|
1214
|
+
}
|
|
1215
|
+
function isCurrent(session) {
|
|
1216
|
+
return deps.session.current().generation === session.generation;
|
|
1217
|
+
}
|
|
1218
|
+
return { startPayment, completePayment, getPayment };
|
|
1219
|
+
}
|
|
1220
|
+
async function attempt(transport, call, spec, expectation) {
|
|
1221
|
+
try {
|
|
1222
|
+
const answer = expectation ? await transport.call(call.method, call.path, call.body, call.headers, expectation) : await transport.call(call.method, call.path, call.body, call.headers);
|
|
1223
|
+
return { answer };
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
return { failure: classifyFailure(error, spec.operation, spec.codes) };
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
async function read(call, operation) {
|
|
1229
|
+
try {
|
|
1230
|
+
return { value: await call() };
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
return { failure: classifyFailure(error, operation, []) };
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
function refused(operation, kind) {
|
|
1236
|
+
return { failure: failure(operation, kind) };
|
|
1237
|
+
}
|
|
1238
|
+
function expectationOf2(scope) {
|
|
1239
|
+
return { appId: scope.binding.purchasesAppId, memberId: scope.memberId };
|
|
1240
|
+
}
|
|
1241
|
+
function refuseProof(transaction) {
|
|
1242
|
+
if (transaction.environment !== "production" && transaction.environment !== "sandbox") return failure("completePayment", "environmentUnsupported");
|
|
1243
|
+
const signed = transaction.signedTransaction;
|
|
1244
|
+
return typeof signed === "string" && signed.length > 0 && signed.length <= MAX_SIGNED_TRANSACTION ? null : failure("completePayment", "invalidArgument");
|
|
1245
|
+
}
|
|
1246
|
+
function isBindingFor(binding, host) {
|
|
1247
|
+
return binding.himalayaAppId === host.appId && binding.bundleId === host.bundleId && binding.siteId === host.siteId;
|
|
1248
|
+
}
|
|
1249
|
+
function bridgeTransport() {
|
|
1250
|
+
const himalaya = globalThis.himalaya;
|
|
1251
|
+
const bridge = himalaya ? himalaya.wixApi : void 0;
|
|
1252
|
+
return typeof bridge?.call === "function" ? bridge : void 0;
|
|
1253
|
+
}
|
|
1254
|
+
var MAX_SIGNED_TRANSACTION = 2e4;
|
|
1255
|
+
var START_PAYMENT_CODES = [
|
|
1256
|
+
"NOT_PENDING",
|
|
1257
|
+
"WRONG_PAYMENT_METHOD",
|
|
1258
|
+
"NOT_ORDER_BUYER",
|
|
1259
|
+
"UNSUPPORTED_ORDER",
|
|
1260
|
+
"PRODUCT_NOT_AVAILABLE",
|
|
1261
|
+
"ALREADY_OWNED"
|
|
1262
|
+
];
|
|
1263
|
+
var COMPLETE_PAYMENT_CODES = [
|
|
1264
|
+
"INVALID_PURCHASE",
|
|
1265
|
+
"OWNED_BY_ANOTHER_CUSTOMER",
|
|
1266
|
+
"PURCHASE_REVOKED",
|
|
1267
|
+
"NOT_PURCHASED",
|
|
1268
|
+
"ZERO_PRICE",
|
|
1269
|
+
"NO_MATCHING_PAYMENT",
|
|
1270
|
+
"PAYMENT_NOT_PENDING",
|
|
1271
|
+
"APP_NOT_CONFIGURED"
|
|
1272
|
+
];
|
|
1273
|
+
var GET_PAYMENT_CODES = ["NOT_FOUND"];
|
|
1274
|
+
|
|
540
1275
|
// ../../core/sdk/iap/src/index.ts
|
|
1276
|
+
async function getProducts(productIds) {
|
|
1277
|
+
if (!productIds || productIds.length === 0) return [];
|
|
1278
|
+
const r = await dispatch("capability.iap.getProducts", {
|
|
1279
|
+
// Product ids are reverse-DNS-ish and never contain commas — comma-join
|
|
1280
|
+
// matches the @himalaya/push list-param convention.
|
|
1281
|
+
productIds: productIds.join(",")
|
|
1282
|
+
});
|
|
1283
|
+
return Array.isArray(r?.products) ? r.products : [];
|
|
1284
|
+
}
|
|
541
1285
|
async function purchaseForVerification(input) {
|
|
542
|
-
if (!
|
|
1286
|
+
if (!nonempty2(input?.productId) || !isUUID2(input?.appAccountToken)) return failure2("invalidArgument");
|
|
543
1287
|
const result = await managedDispatch(() => dispatch("capability.iap.purchaseForVerification", input));
|
|
544
1288
|
if (result?.status === "purchased" && isAppleTransaction(result.transaction)) {
|
|
545
1289
|
return { status: "purchased", transaction: decodeTransaction(result.transaction) };
|
|
@@ -555,21 +1299,57 @@ async function getUnfinishedTransactions() {
|
|
|
555
1299
|
return decodeFailure(result);
|
|
556
1300
|
}
|
|
557
1301
|
async function finishTransaction(input) {
|
|
558
|
-
if (!
|
|
1302
|
+
if (!nonempty2(input?.transactionId)) return failure2("invalidArgument");
|
|
559
1303
|
const result = await managedDispatch(() => dispatch("capability.iap.finishTransaction", input));
|
|
560
1304
|
if (result?.status === "finished" || result?.status === "notFound") return { status: result.status };
|
|
561
1305
|
return decodeFailure(result);
|
|
562
1306
|
}
|
|
563
1307
|
var appleManagedStore = { purchaseForVerification, getUnfinishedTransactions, finishTransaction };
|
|
1308
|
+
function hostAppBindingSource() {
|
|
1309
|
+
let read2;
|
|
1310
|
+
return {
|
|
1311
|
+
current: () => read2 ?? (read2 = readHostBinding().catch((error) => {
|
|
1312
|
+
read2 = void 0;
|
|
1313
|
+
throw error;
|
|
1314
|
+
}))
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
async function readHostBinding() {
|
|
1318
|
+
let answer;
|
|
1319
|
+
try {
|
|
1320
|
+
answer = await dispatch("capability.iap.appBinding");
|
|
1321
|
+
} catch (error) {
|
|
1322
|
+
if (bindingNotOffered(error)) return null;
|
|
1323
|
+
throw new Error("the host could not read the app binding");
|
|
1324
|
+
}
|
|
1325
|
+
if (!isObject4(answer)) throw new Error("the host could not read the app binding");
|
|
1326
|
+
if (answer.status === "bound") return decodeBinding(answer.binding);
|
|
1327
|
+
if (answer.status === "unbound" || answer.status === "failed" && answer.code === "unsupported") return null;
|
|
1328
|
+
throw new Error("the host could not read the app binding");
|
|
1329
|
+
}
|
|
1330
|
+
function bindingNotOffered(error) {
|
|
1331
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1332
|
+
return /(unknown|no capability handler for|needs a fixture for)\W[^\n]{0,20}capability\.iap\.appBinding|capability iap not allowed/i.test(message);
|
|
1333
|
+
}
|
|
1334
|
+
var shared;
|
|
1335
|
+
function sharedHostAppBindingSource() {
|
|
1336
|
+
return shared ?? (shared = hostAppBindingSource());
|
|
1337
|
+
}
|
|
1338
|
+
function decodeBinding(raw) {
|
|
1339
|
+
if (!isObject4(raw)) return null;
|
|
1340
|
+
const { purchasesAppId, himalayaAppId, bundleId, siteId } = raw;
|
|
1341
|
+
if (!isUUID2(purchasesAppId) || !isUUID2(siteId) || !nonempty2(himalayaAppId) || !nonempty2(bundleId)) return null;
|
|
1342
|
+
return { purchasesAppId, himalayaAppId, bundleId, siteId };
|
|
1343
|
+
}
|
|
564
1344
|
var transactionErrors = /* @__PURE__ */ new Set(["unsupported", "unavailable", "invalidArgument", "invalidResponse", "notEnabled", "unsupportedProductType", "unknownProduct", "verificationFailed", "persistenceFailed", "ownershipConflict", "storeError", "busy"]);
|
|
565
1345
|
var failure2 = (code) => ({ status: "failed", code });
|
|
566
|
-
var
|
|
1346
|
+
var nonempty2 = (value) => typeof value === "string" && value.trim().length > 0;
|
|
567
1347
|
var isUUID2 = (value) => typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value) && value.length === 36;
|
|
568
|
-
var
|
|
1348
|
+
var isObject4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
569
1349
|
async function managedDispatch(invoke) {
|
|
570
1350
|
try {
|
|
571
1351
|
const value = await invoke();
|
|
572
|
-
return
|
|
1352
|
+
return isObject4(value) ? value : null;
|
|
573
1353
|
} catch {
|
|
574
1354
|
return failure2("unavailable");
|
|
575
1355
|
}
|
|
@@ -578,14 +1358,26 @@ function decodeFailure(value) {
|
|
|
578
1358
|
return value?.status === "failed" && transactionErrors.has(value.code) ? failure2(value.code) : failure2("invalidResponse");
|
|
579
1359
|
}
|
|
580
1360
|
function isAppleTransaction(value) {
|
|
581
|
-
if (!
|
|
582
|
-
return value.store === "apple" && typeof value.signedTransaction === "string" && /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.signedTransaction) &&
|
|
1361
|
+
if (!isObject4(value)) return false;
|
|
1362
|
+
return value.store === "apple" && typeof value.signedTransaction === "string" && /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.signedTransaction) && nonempty2(value.transactionId) && nonempty2(value.originalTransactionId) && nonempty2(value.productId) && (value.appAccountToken === null || isUUID2(value.appAccountToken)) && ["production", "sandbox", "xcode", "unknown"].includes(value.environment);
|
|
583
1363
|
}
|
|
584
1364
|
function decodeTransaction(value) {
|
|
585
1365
|
const { store, signedTransaction, transactionId, originalTransactionId, productId, appAccountToken, environment } = value;
|
|
586
1366
|
return { store, signedTransaction, transactionId, originalTransactionId, productId, appAccountToken, environment };
|
|
587
1367
|
}
|
|
588
1368
|
|
|
1369
|
+
// ../../stdlib/flows/iap-checkout/src/checkout-source.ts
|
|
1370
|
+
var HIMALAYA_SERVE_CHECKOUT_ROUTES = {
|
|
1371
|
+
wixIap: HIMALAYA_SERVE_IAP_ROUTE,
|
|
1372
|
+
cashier: { prefix: HIMALAYA_SERVE_IAP_ROUTE.prefix }
|
|
1373
|
+
};
|
|
1374
|
+
function appleIapCheckoutRoutes() {
|
|
1375
|
+
return HIMALAYA_SERVE_CHECKOUT_ROUTES;
|
|
1376
|
+
}
|
|
1377
|
+
function appleIapCheckoutEnabled() {
|
|
1378
|
+
return appleIapCheckoutRoutes() !== null;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
589
1381
|
// ../../stdlib/flows/iap-checkout/src/cashier-charges.ts
|
|
590
1382
|
async function ensureAppleIapCharge(bridge, route, orderId) {
|
|
591
1383
|
if (!isRoutePrefix2(route.prefix)) return { status: "notConfigured" };
|
|
@@ -622,22 +1414,22 @@ function decideFromCharges(charges) {
|
|
|
622
1414
|
return isAwaitingApple(apple) ? { status: "pending", transactionId: apple.transactionId } : { status: "invalidResponse" };
|
|
623
1415
|
}
|
|
624
1416
|
function chargedFrom(body) {
|
|
625
|
-
const charge =
|
|
1417
|
+
const charge = isObject5(body) ? decodeCharge(body.charge) : null;
|
|
626
1418
|
return charge && isAwaitingApple(charge) ? { status: "pending", transactionId: charge.transactionId } : null;
|
|
627
1419
|
}
|
|
628
1420
|
function isAwaitingApple(charge) {
|
|
629
1421
|
return charge.paymentMethod === APPLE_IAP && AWAITING_PAYMENT.has(charge.status);
|
|
630
1422
|
}
|
|
631
1423
|
function decodeCharges(body) {
|
|
632
|
-
if (!
|
|
1424
|
+
if (!isObject5(body)) return null;
|
|
633
1425
|
const raw = body.charges ?? [];
|
|
634
1426
|
if (!Array.isArray(raw)) return null;
|
|
635
1427
|
const charges = raw.map(decodeCharge);
|
|
636
1428
|
return charges.every((charge) => charge !== null) ? charges : null;
|
|
637
1429
|
}
|
|
638
1430
|
function decodeCharge(raw) {
|
|
639
|
-
if (!
|
|
640
|
-
const state =
|
|
1431
|
+
if (!isObject5(raw) || !isNonEmpty2(raw.chargeId) || !isNonEmpty2(raw.transactionId)) return null;
|
|
1432
|
+
const state = isObject5(raw.state) && isObject5(raw.state.transactionStatus) ? raw.state.transactionStatus : {};
|
|
641
1433
|
const method = isNonEmpty2(raw.paymentMethodId) ? raw.paymentMethodId : isNonEmpty2(raw.paymentMethod) ? raw.paymentMethod : "";
|
|
642
1434
|
return { chargeId: raw.chargeId, transactionId: raw.transactionId, status: isNonEmpty2(state.status) ? state.status : "UNDEFINED", paymentMethod: method };
|
|
643
1435
|
}
|
|
@@ -650,7 +1442,7 @@ function chargesPath(route, orderId) {
|
|
|
650
1442
|
function isRoutePrefix2(prefix) {
|
|
651
1443
|
return /^\/[A-Za-z0-9._~\-/]*[A-Za-z0-9._~-]$/.test(prefix);
|
|
652
1444
|
}
|
|
653
|
-
function
|
|
1445
|
+
function isObject5(value) {
|
|
654
1446
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
655
1447
|
}
|
|
656
1448
|
function isNonEmpty2(value) {
|
|
@@ -749,7 +1541,7 @@ function readVersioned(store, location) {
|
|
|
749
1541
|
if (raw === void 0) return null;
|
|
750
1542
|
if (raw === null || raw === "") return "empty";
|
|
751
1543
|
const parsed = safely(() => JSON.parse(raw));
|
|
752
|
-
return
|
|
1544
|
+
return isObject6(parsed) && parsed.v === VERSION ? parsed : null;
|
|
753
1545
|
}
|
|
754
1546
|
function writeVerified(store, location, value) {
|
|
755
1547
|
if (!store) return false;
|
|
@@ -759,7 +1551,7 @@ function writeVerified(store, location, value) {
|
|
|
759
1551
|
}) === true;
|
|
760
1552
|
}
|
|
761
1553
|
function isOrderRef(value) {
|
|
762
|
-
if (!
|
|
1554
|
+
if (!isObject6(value) || typeof value.key !== "string" || !STAGES.has(value.stage)) return false;
|
|
763
1555
|
if (typeof value.updatedAt !== "number") return false;
|
|
764
1556
|
const optional = ["kind", "cashierOrderId", "wixTransactionId", "paymentId", "storeProductId", "appProductId", "appleTransactionId", "appAccountToken"];
|
|
765
1557
|
if (!optional.every((field) => value[field] === void 0 || typeof value[field] === "string")) return false;
|
|
@@ -794,9 +1586,9 @@ function hostStorage() {
|
|
|
794
1586
|
const storage = globalThis.himalaya?.storage;
|
|
795
1587
|
return typeof storage?.getItem === "function" && typeof storage.setItem === "function" ? storage : void 0;
|
|
796
1588
|
}
|
|
797
|
-
function safely(
|
|
1589
|
+
function safely(read2) {
|
|
798
1590
|
try {
|
|
799
|
-
return
|
|
1591
|
+
return read2();
|
|
800
1592
|
} catch {
|
|
801
1593
|
return void 0;
|
|
802
1594
|
}
|
|
@@ -805,9 +1597,9 @@ function serialize(value) {
|
|
|
805
1597
|
return JSON.stringify(value);
|
|
806
1598
|
}
|
|
807
1599
|
function isStringMap(value) {
|
|
808
|
-
return
|
|
1600
|
+
return isObject6(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
809
1601
|
}
|
|
810
|
-
function
|
|
1602
|
+
function isObject6(value) {
|
|
811
1603
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
812
1604
|
}
|
|
813
1605
|
function isUUID3(value) {
|
|
@@ -826,7 +1618,7 @@ function bindBridge(session, provider, bridge) {
|
|
|
826
1618
|
if (!isCurrent()) return SESSION_CHANGED;
|
|
827
1619
|
const expectation = boundExpectation(session, provider, bridge);
|
|
828
1620
|
if (expectation === "refuse") return { status: "notEnabled" };
|
|
829
|
-
const outcome = await
|
|
1621
|
+
const outcome = await attempt2(bridge, method, path, body, expectation);
|
|
830
1622
|
return isCurrent() ? outcome : SESSION_CHANGED;
|
|
831
1623
|
}
|
|
832
1624
|
return { call, isCurrent };
|
|
@@ -837,7 +1629,7 @@ function hostBridge() {
|
|
|
837
1629
|
return typeof bridge?.call === "function" ? bridge : void 0;
|
|
838
1630
|
}
|
|
839
1631
|
var MISSING_BRIDGE = { call: () => Promise.reject(new Error("wixApi not enabled")) };
|
|
840
|
-
async function
|
|
1632
|
+
async function attempt2(bridge, method, path, body, expectation) {
|
|
841
1633
|
try {
|
|
842
1634
|
const answer = expectation ? await bridge.call(method, path, body, void 0, expectation) : await bridge.call(method, path, body);
|
|
843
1635
|
return { status: "ok", body: answer };
|
|
@@ -859,8 +1651,8 @@ function isLiveHost(bridge) {
|
|
|
859
1651
|
function refusalOf(error) {
|
|
860
1652
|
const message = error?.message;
|
|
861
1653
|
const text = typeof message === "string" ? message : "";
|
|
862
|
-
if (
|
|
863
|
-
if (
|
|
1654
|
+
if (BRIDGE_REFUSAL2.test(text)) return { status: "notEnabled" };
|
|
1655
|
+
if (PRINCIPAL_CHANGED2.test(text)) return SESSION_CHANGED;
|
|
864
1656
|
const http = /^HTTP (\d{3})(?: \[([^\]]+)\])?:/.exec(text);
|
|
865
1657
|
if (!http) return { status: "unavailable" };
|
|
866
1658
|
return httpRefusal(Number(http[1]), http[2] ?? "");
|
|
@@ -871,8 +1663,8 @@ function httpRefusal(httpStatus, code) {
|
|
|
871
1663
|
return { status: "http", httpStatus, code };
|
|
872
1664
|
}
|
|
873
1665
|
var SESSION_CHANGED = { status: "sessionChanged" };
|
|
874
|
-
var
|
|
875
|
-
var
|
|
1666
|
+
var BRIDGE_REFUSAL2 = /^(wixApi not enabled|capability wix_api not allowed)\b|^NotInstalled\(\)$/;
|
|
1667
|
+
var PRINCIPAL_CHANGED2 = /^PRINCIPAL_CHANGED\b/;
|
|
876
1668
|
|
|
877
1669
|
// ../../stdlib/flows/iap-checkout/src/iap-order-backend.ts
|
|
878
1670
|
function createWixOrderBackend(deps) {
|
|
@@ -934,26 +1726,26 @@ function createWixOrderBackend(deps) {
|
|
|
934
1726
|
if (existing?.stage === "held") return stopWith("rejected", "paymentHeld");
|
|
935
1727
|
if (existing?.stage === "needsSupport") return stopWith("rejected", "needsSupport");
|
|
936
1728
|
if (deps.productBusy?.(sale.appleProduct.productId)) return stopWith("rejected", "paymentInProgress");
|
|
937
|
-
const
|
|
938
|
-
return recordOrder(sale, existing,
|
|
1729
|
+
const attempt3 = existing?.cashierOrderId && existing.verticalRef ? await reopenOrOpen(sale, { cashierOrderId: existing.cashierOrderId, verticalRef: existing.verticalRef }) : await sale.adapter.openOrder(sale.item, sale.bridge);
|
|
1730
|
+
return recordOrder(sale, existing, attempt3);
|
|
939
1731
|
}
|
|
940
1732
|
async function reopenOrOpen(sale, order) {
|
|
941
1733
|
const reopened = await sale.adapter.reopenOrder(order, sale.bridge);
|
|
942
1734
|
const closed = reopened.status === "refused" && reopened.reason === "orderClosed";
|
|
943
1735
|
return closed ? sale.adapter.openOrder(sale.item, sale.bridge) : reopened;
|
|
944
1736
|
}
|
|
945
|
-
function recordOrder(sale, existing,
|
|
946
|
-
if (
|
|
947
|
-
if (
|
|
948
|
-
if (
|
|
949
|
-
const kept = existing && existing.cashierOrderId ===
|
|
1737
|
+
function recordOrder(sale, existing, attempt3) {
|
|
1738
|
+
if (attempt3.status === "granted") return alreadyOwned(sale);
|
|
1739
|
+
if (attempt3.status === "refused") return stopWith("rejected", attempt3.reason);
|
|
1740
|
+
if (attempt3.status !== "open") return attempt3.status === "sessionChanged" ? STALE2 : retry("unavailable");
|
|
1741
|
+
const kept = existing && existing.cashierOrderId === attempt3.cashierOrderId ? existing : { key: sale.catalogRef, updatedAt: 0 };
|
|
950
1742
|
return persist(sale, {
|
|
951
1743
|
...kept,
|
|
952
1744
|
key: sale.catalogRef,
|
|
953
1745
|
stage: "ordered",
|
|
954
1746
|
kind: sale.adapter.kind,
|
|
955
|
-
verticalRef:
|
|
956
|
-
cashierOrderId:
|
|
1747
|
+
verticalRef: attempt3.verticalRef,
|
|
1748
|
+
cashierOrderId: attempt3.cashierOrderId,
|
|
957
1749
|
updatedAt: now()
|
|
958
1750
|
});
|
|
959
1751
|
}
|
|
@@ -1194,6 +1986,8 @@ function enabledCheckout(deps) {
|
|
|
1194
1986
|
const bridge = deps.bridge ?? hostBridge() ?? MISSING_BRIDGE;
|
|
1195
1987
|
const sales = /* @__PURE__ */ new Map();
|
|
1196
1988
|
const payments = /* @__PURE__ */ new Map();
|
|
1989
|
+
const readGrants = /* @__PURE__ */ new Set();
|
|
1990
|
+
const accessReads = /* @__PURE__ */ new Map();
|
|
1197
1991
|
let current = { item: null, failure: null, buying: false };
|
|
1198
1992
|
let generation = deps.session.current().generation;
|
|
1199
1993
|
let disposed = false;
|
|
@@ -1229,6 +2023,28 @@ function enabledCheckout(deps) {
|
|
|
1229
2023
|
await trackPayments({ dueOnly: false });
|
|
1230
2024
|
return state();
|
|
1231
2025
|
}
|
|
2026
|
+
async function checkAccess(items) {
|
|
2027
|
+
resetIfSessionChanged();
|
|
2028
|
+
const session = deps.session.current();
|
|
2029
|
+
if (session.kind !== "member") return state();
|
|
2030
|
+
for (const item of items) {
|
|
2031
|
+
const key = itemKey(item);
|
|
2032
|
+
const adapter = deps.adapters.find((candidate) => candidate.kind === item.reference.kind);
|
|
2033
|
+
if (!adapter?.currentAccess || payments.has(key) && payments.get(key).access !== "granted" && !readGrants.has(key)) continue;
|
|
2034
|
+
const seq = (accessReads.get(key) ?? 0) + 1;
|
|
2035
|
+
accessReads.set(key, seq);
|
|
2036
|
+
const access = await adapter.currentAccess(item, bindBridge(session, deps.session, bridge)).catch(() => "unavailable");
|
|
2037
|
+
if (deps.session.current().generation !== session.generation) break;
|
|
2038
|
+
if (accessReads.get(key) !== seq) continue;
|
|
2039
|
+
if (access === "granted") {
|
|
2040
|
+
setPayment(key, "granted");
|
|
2041
|
+
readGrants.add(key);
|
|
2042
|
+
} else if (access === "none" && readGrants.delete(key)) {
|
|
2043
|
+
payments.delete(key);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
return publishAndReturn();
|
|
2047
|
+
}
|
|
1232
2048
|
async function buy(item) {
|
|
1233
2049
|
resetIfSessionChanged();
|
|
1234
2050
|
const key = itemKey(item);
|
|
@@ -1287,6 +2103,7 @@ function enabledCheckout(deps) {
|
|
|
1287
2103
|
const access = owned ? "granted" : event.access;
|
|
1288
2104
|
const failure3 = owned ? void 0 : event.failure;
|
|
1289
2105
|
if (access) setPayment(event.key, access);
|
|
2106
|
+
if (owned) readGrants.add(event.key);
|
|
1290
2107
|
if (labelOf(event.key) === current.item && (failure3 || access)) current.failure = failure3 ?? failureOfAccess(access);
|
|
1291
2108
|
}
|
|
1292
2109
|
function setPayment(key, access) {
|
|
@@ -1323,6 +2140,7 @@ function enabledCheckout(deps) {
|
|
|
1323
2140
|
generation = next;
|
|
1324
2141
|
sales.clear();
|
|
1325
2142
|
payments.clear();
|
|
2143
|
+
readGrants.clear();
|
|
1326
2144
|
awaitingApproval.clear();
|
|
1327
2145
|
partitionRead = null;
|
|
1328
2146
|
current = { item: null, failure: null, buying: false };
|
|
@@ -1392,10 +2210,10 @@ function enabledCheckout(deps) {
|
|
|
1392
2210
|
return readDue || [...payments.values()].some((payment) => payment.access === "processing" && isDue(payment.key, true));
|
|
1393
2211
|
}
|
|
1394
2212
|
async function trackOne(session, partition, ref) {
|
|
1395
|
-
const
|
|
2213
|
+
const read2 = await deps.wixIap.getPayment({ paymentId: ref.paymentId ?? "" });
|
|
1396
2214
|
if (!isCurrent(session)) return;
|
|
1397
|
-
if (
|
|
1398
|
-
await settlePayment(session, partition, ref,
|
|
2215
|
+
if (read2.status !== "found") return read2.kind === "application" ? markNeedsSupport(partition, ref) : backOff(partition, ref, false);
|
|
2216
|
+
await settlePayment(session, partition, ref, read2.payment);
|
|
1399
2217
|
}
|
|
1400
2218
|
async function settlePayment(session, partition, ref, payment) {
|
|
1401
2219
|
if (isFinalRefusal(payment.status)) return markNeedsSupport(partition, ref);
|
|
@@ -1446,12 +2264,15 @@ function enabledCheckout(deps) {
|
|
|
1446
2264
|
function isCurrent(session) {
|
|
1447
2265
|
return !disposed && deps.session.current().generation === session.generation;
|
|
1448
2266
|
}
|
|
1449
|
-
return { start, buy, reconcile: reconcile2, retry: retry2, tick, state, dispose };
|
|
2267
|
+
return { start, buy, checkAccess, reconcile: reconcile2, retry: retry2, tick, state, dispose };
|
|
2268
|
+
}
|
|
2269
|
+
function notEnabledState() {
|
|
2270
|
+
return blankState(false);
|
|
1450
2271
|
}
|
|
1451
2272
|
function disabledCheckout() {
|
|
1452
2273
|
const state = () => blankState(false);
|
|
1453
2274
|
const resolved = () => Promise.resolve(state());
|
|
1454
|
-
return { start: resolved, buy: resolved, reconcile: resolved, retry: resolved, tick: resolved, state, dispose: () => {
|
|
2275
|
+
return { start: resolved, buy: resolved, checkAccess: resolved, reconcile: resolved, retry: resolved, tick: resolved, state, dispose: () => {
|
|
1455
2276
|
} };
|
|
1456
2277
|
}
|
|
1457
2278
|
function blankState(enabled) {
|
|
@@ -1499,6 +2320,307 @@ function failureOfAccess(access) {
|
|
|
1499
2320
|
var BASE_DELAY_MS = 1e3;
|
|
1500
2321
|
var OVERLAY_PHASES = /* @__PURE__ */ new Set(["purchasing", "awaitingApproval", "cancelled", "signInRequired", "unavailable"]);
|
|
1501
2322
|
|
|
2323
|
+
// ../../stdlib/flows/iap-checkout/src/purchase-fields.ts
|
|
2324
|
+
function iapPurchaseFields(view, state, readiness, copy) {
|
|
2325
|
+
const key = `${view.reference.kind}:${view.reference.id}`;
|
|
2326
|
+
if (view.route !== "appleIap" && !holdsSale(state, key)) return { ...action(copy, "enabled", ""), appleRoute: false };
|
|
2327
|
+
if (readiness.status !== "ready") return action(copy, "disabled", readiness.status === "checking" ? "" : copy.unavailable);
|
|
2328
|
+
const own = state.item === key;
|
|
2329
|
+
const payment = state.payments.find((tracked) => tracked.item === key)?.access;
|
|
2330
|
+
if (own && state.phase === "accessReady" || payment === "granted") return { ...action(copy, "disabled", ""), accessReady: true };
|
|
2331
|
+
if (IN_FLIGHT.has(state.phase)) return action(copy, "busy", own ? copy.processing : "");
|
|
2332
|
+
if (own) return outcomeAction(state, copy);
|
|
2333
|
+
if (payment === "processing") return action(copy, "busy", copy.processing);
|
|
2334
|
+
if (payment === "needsSupport") return action(copy, "disabled", copy.support);
|
|
2335
|
+
return action(copy, "enabled", "");
|
|
2336
|
+
}
|
|
2337
|
+
function holdsSale(state, key) {
|
|
2338
|
+
if (state.payments.some((tracked) => tracked.item === key)) return true;
|
|
2339
|
+
return state.item === key && (SALE_PHASES.has(state.phase) || state.purchase.phase === "awaitingApproval");
|
|
2340
|
+
}
|
|
2341
|
+
function outcomeAction(state, copy) {
|
|
2342
|
+
if (state.purchase.phase === "awaitingApproval") return action(copy, "disabled", copy.awaitingApproval);
|
|
2343
|
+
switch (state.phase) {
|
|
2344
|
+
case "awaitingApproval":
|
|
2345
|
+
return action(copy, "disabled", copy.awaitingApproval);
|
|
2346
|
+
case "signInRequired":
|
|
2347
|
+
return action(copy, "disabled", copy.signInRequired);
|
|
2348
|
+
case "unavailable":
|
|
2349
|
+
return action(copy, "enabled", copy.retry);
|
|
2350
|
+
case "refused":
|
|
2351
|
+
return refusalAction(state.failure, copy);
|
|
2352
|
+
case "notEnabled":
|
|
2353
|
+
return action(copy, "disabled", copy.unavailable);
|
|
2354
|
+
default:
|
|
2355
|
+
return action(copy, "enabled", "");
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
function refusalAction(failure3, copy) {
|
|
2359
|
+
const [mode, note] = REFUSALS[failure3 ?? "unavailable"] ?? ["enabled", "retry"];
|
|
2360
|
+
return action(copy, mode, note ? copy[note] : "");
|
|
2361
|
+
}
|
|
2362
|
+
function action(copy, mode, note) {
|
|
2363
|
+
return { appleRoute: true, accessReady: false, buyLabel: copy.buy, buyDisabled: mode !== "enabled", buyBusy: mode === "busy", buyNote: note };
|
|
2364
|
+
}
|
|
2365
|
+
var IN_FLIGHT = /* @__PURE__ */ new Set(["preparing", "purchasing", "processing"]);
|
|
2366
|
+
var SALE_PHASES = /* @__PURE__ */ new Set([...IN_FLIGHT, "awaitingApproval", "accessReady"]);
|
|
2367
|
+
var REFUSALS = {
|
|
2368
|
+
productChanged: ["enabled", "priceChanged"],
|
|
2369
|
+
paymentHeld: ["disabled", "support"],
|
|
2370
|
+
needsSupport: ["disabled", "support"],
|
|
2371
|
+
invalidAssociation: ["disabled", "support"],
|
|
2372
|
+
// Nothing in the checkout clears this, so the action stays tappable: a tap re-reads the order
|
|
2373
|
+
// (never a second charge) and turns into access once the vertical grants it.
|
|
2374
|
+
paymentInProgress: ["enabled", "processing"],
|
|
2375
|
+
approvalRequired: ["disabled", "awaitingApproval"],
|
|
2376
|
+
signInRequired: ["disabled", "signInRequired"],
|
|
2377
|
+
notConfigured: ["disabled", "unavailable"],
|
|
2378
|
+
notEnabled: ["disabled", "unavailable"],
|
|
2379
|
+
storageUnavailable: ["disabled", "unavailable"],
|
|
2380
|
+
unsupportedItem: ["disabled", "unavailable"],
|
|
2381
|
+
// The action shows only on an App Store route, so a refusal for any other route is stale.
|
|
2382
|
+
notAppleRoute: ["enabled", null]
|
|
2383
|
+
};
|
|
2384
|
+
|
|
2385
|
+
// ../../stdlib/flows/iap-checkout/src/commerce-core.ts
|
|
2386
|
+
function createIapCommerceWith(deps) {
|
|
2387
|
+
let readiness = { status: "checking" };
|
|
2388
|
+
let checkout;
|
|
2389
|
+
let opening;
|
|
2390
|
+
let disposed = false;
|
|
2391
|
+
let armedInterval = null;
|
|
2392
|
+
let lastPollAt = null;
|
|
2393
|
+
let lastPricedAt = null;
|
|
2394
|
+
let pricedItems = null;
|
|
2395
|
+
let lastScopeComplete = true;
|
|
2396
|
+
let stopWatchingSession;
|
|
2397
|
+
let stopWatchingAccess;
|
|
2398
|
+
let checkoutStarted = false;
|
|
2399
|
+
let recheckAfterOpening = false;
|
|
2400
|
+
async function loadPrices(items) {
|
|
2401
|
+
if (!deps.pricing.enabled) return { scopeComplete: true };
|
|
2402
|
+
lastPricedAt = deps.clock.now();
|
|
2403
|
+
pricedItems = items;
|
|
2404
|
+
const [identity, read2] = await Promise.all([deps.host.identity(), deps.binding.current().then((binding) => ({ binding }), () => null)]);
|
|
2405
|
+
const scope = read2 ? catalogScope(identity, read2.binding) : { appId: "", bundleId: "" };
|
|
2406
|
+
await deps.pricing.load({ scope, platform: identity?.platform ?? "", items });
|
|
2407
|
+
lastScopeComplete = identity !== null && read2 !== null;
|
|
2408
|
+
if (checkout) await checkAccess(checkout);
|
|
2409
|
+
return { scopeComplete: lastScopeComplete };
|
|
2410
|
+
}
|
|
2411
|
+
function pollDirective(action2) {
|
|
2412
|
+
const interval = checkout?.state().nextWakeAt != null ? DUE_WORK_POLL_MS : deps.pricing.enabled || checkout ? PRICE_REFRESH_MS : null;
|
|
2413
|
+
if (interval === null || interval === armedInterval) return void 0;
|
|
2414
|
+
armedInterval = interval;
|
|
2415
|
+
lastPollAt ?? (lastPollAt = deps.clock.now());
|
|
2416
|
+
return { id: POLL_ID2, action: action2, intervalMs: interval, immediate: true };
|
|
2417
|
+
}
|
|
2418
|
+
async function poll() {
|
|
2419
|
+
const now = deps.clock.now();
|
|
2420
|
+
const suspended = lastPollAt !== null && now - lastPollAt > SUSPENDED_AFTER_MS;
|
|
2421
|
+
lastPollAt = now;
|
|
2422
|
+
await (suspended ? reconcile2() : checkout ? checkout.tick() : startedCheckout());
|
|
2423
|
+
if (pricedItems && lastPricedAt !== null && now - lastPricedAt >= PRICE_REFRESH_MS - PRICE_REFRESH_SLACK_MS) await loadPrices(pricedItems);
|
|
2424
|
+
}
|
|
2425
|
+
function reconcile2() {
|
|
2426
|
+
return recover((opened) => opened.reconcile());
|
|
2427
|
+
}
|
|
2428
|
+
function start() {
|
|
2429
|
+
return recover((opened) => opened.start());
|
|
2430
|
+
}
|
|
2431
|
+
async function buy(item) {
|
|
2432
|
+
if (unanswered2(deps.pricing.view(item.reference))) return state();
|
|
2433
|
+
const started = await startedCheckout();
|
|
2434
|
+
return started ? started.opened.buy(item) : state();
|
|
2435
|
+
}
|
|
2436
|
+
function purchaseFields(reference, copy) {
|
|
2437
|
+
const view = deps.pricing.view(reference);
|
|
2438
|
+
const fields = iapPurchaseFields({ ...view, route: deps.pricing.continueCheckoutGuard(reference).route }, state(), readiness, copy);
|
|
2439
|
+
if (!fields.appleRoute || fields.accessReady || fields.buyDisabled) return fields;
|
|
2440
|
+
if (deps.session.current().kind !== "member") return { ...fields, buyDisabled: true, buyNote: copy.signInRequired };
|
|
2441
|
+
if (!unanswered2(view)) return fields;
|
|
2442
|
+
return { ...fields, buyDisabled: true, buyNote: view.reason === "mappingUnavailable" ? copy.unavailable : fields.buyNote };
|
|
2443
|
+
}
|
|
2444
|
+
function catalogScope(identity, binding) {
|
|
2445
|
+
const siteId = binding?.siteId ?? (identity?.platform === "web" ? "" : deps.host.preferenceSite());
|
|
2446
|
+
return { appId: identity?.appId ?? "", bundleId: identity?.bundleId ?? "", ...siteId ? { siteId } : {} };
|
|
2447
|
+
}
|
|
2448
|
+
function open() {
|
|
2449
|
+
if (checkout || disposed) return Promise.resolve(checkout);
|
|
2450
|
+
return opening ?? (opening = openWhenReady().finally(() => {
|
|
2451
|
+
opening = void 0;
|
|
2452
|
+
if (!recheckAfterOpening) return;
|
|
2453
|
+
recheckAfterOpening = false;
|
|
2454
|
+
if (!checkout && !disposed) void startedCheckout();
|
|
2455
|
+
}));
|
|
2456
|
+
}
|
|
2457
|
+
async function openWhenReady() {
|
|
2458
|
+
const staticGaps = configurationGaps();
|
|
2459
|
+
if (staticGaps.length > 0) return settle({ status: "unavailable", gaps: staticGaps });
|
|
2460
|
+
const routes = deps.routes;
|
|
2461
|
+
const [identity, binding] = await Promise.all([deps.host.identity(), readBinding2()]);
|
|
2462
|
+
const host = identity && binding && hostFor(identity, binding);
|
|
2463
|
+
const gaps = await hostGaps(host, binding);
|
|
2464
|
+
if (!host || gaps.length > 0 || disposed) {
|
|
2465
|
+
watchSessionUntilReady();
|
|
2466
|
+
return settle({ status: "unavailable", gaps });
|
|
2467
|
+
}
|
|
2468
|
+
stopWatchingSession?.();
|
|
2469
|
+
stopWatchingSession = void 0;
|
|
2470
|
+
checkout = createAppleIapCheckoutWith({
|
|
2471
|
+
enabled: true,
|
|
2472
|
+
wixIap: deps.wixIapClient({ host, route: routes.wixIap }),
|
|
2473
|
+
binding: deps.binding,
|
|
2474
|
+
session: deps.session,
|
|
2475
|
+
identity: deps.identity,
|
|
2476
|
+
clock: deps.clock,
|
|
2477
|
+
cashier: routes.cashier,
|
|
2478
|
+
adapters: deps.adapters,
|
|
2479
|
+
pricing: deps.pricing,
|
|
2480
|
+
store: deps.store,
|
|
2481
|
+
refs: deps.refs,
|
|
2482
|
+
bridge: deps.bridge,
|
|
2483
|
+
jitter: deps.jitter,
|
|
2484
|
+
onState: () => deps.onChange?.()
|
|
2485
|
+
});
|
|
2486
|
+
return settle({ status: "ready" });
|
|
2487
|
+
}
|
|
2488
|
+
function watchSessionUntilReady() {
|
|
2489
|
+
stopWatchingSession ?? (stopWatchingSession = deps.session.subscribe(() => {
|
|
2490
|
+
if (checkout || disposed) return;
|
|
2491
|
+
if (opening) recheckAfterOpening = true;
|
|
2492
|
+
else void startedCheckout();
|
|
2493
|
+
}));
|
|
2494
|
+
}
|
|
2495
|
+
function configurationGaps() {
|
|
2496
|
+
return [...deps.routes ? [] : ["routes"], ...deps.pricing.enabled ? [] : ["mapping"]];
|
|
2497
|
+
}
|
|
2498
|
+
async function hostGaps(host, binding) {
|
|
2499
|
+
if (!host) return ["binding"];
|
|
2500
|
+
if (!fencedTo(binding)) return ["nativeIdentity"];
|
|
2501
|
+
const gaps = [];
|
|
2502
|
+
if (!await managedStoreEnabled()) gaps.push("managedStore");
|
|
2503
|
+
if (binding && deps.refs.hasRefs(binding) === null) gaps.push("storage");
|
|
2504
|
+
return gaps;
|
|
2505
|
+
}
|
|
2506
|
+
function fencedTo(binding) {
|
|
2507
|
+
const site = deps.session.site?.();
|
|
2508
|
+
return deps.session.identityBound === true && !!binding && !!site && site.toLowerCase() === binding.siteId.toLowerCase();
|
|
2509
|
+
}
|
|
2510
|
+
async function managedStoreEnabled() {
|
|
2511
|
+
const unfinished = await deps.store.getUnfinishedTransactions().catch(() => null);
|
|
2512
|
+
return unfinished?.status === "ok";
|
|
2513
|
+
}
|
|
2514
|
+
function settle(next) {
|
|
2515
|
+
const changed = JSON.stringify(next) !== JSON.stringify(readiness);
|
|
2516
|
+
readiness = next;
|
|
2517
|
+
if (changed) deps.onChange?.();
|
|
2518
|
+
return checkout;
|
|
2519
|
+
}
|
|
2520
|
+
function readBinding2() {
|
|
2521
|
+
return deps.binding.current().catch(() => null);
|
|
2522
|
+
}
|
|
2523
|
+
async function startedCheckout() {
|
|
2524
|
+
if (deps.adapters.length === 0) return void 0;
|
|
2525
|
+
const opened = await open();
|
|
2526
|
+
if (!opened) return void 0;
|
|
2527
|
+
if (checkoutStarted) return { opened, fresh: false };
|
|
2528
|
+
checkoutStarted = true;
|
|
2529
|
+
await opened.start();
|
|
2530
|
+
stopWatchingAccess = deps.session.subscribe(() => {
|
|
2531
|
+
if (!disposed) void checkAccess(opened);
|
|
2532
|
+
});
|
|
2533
|
+
await checkAccess(opened);
|
|
2534
|
+
return { opened, fresh: true };
|
|
2535
|
+
}
|
|
2536
|
+
async function recover(run) {
|
|
2537
|
+
const started = await startedCheckout();
|
|
2538
|
+
if (!started) return state();
|
|
2539
|
+
if (started.fresh) return state();
|
|
2540
|
+
await run(started.opened);
|
|
2541
|
+
return checkAccess(started.opened);
|
|
2542
|
+
}
|
|
2543
|
+
function checkAccess(opened) {
|
|
2544
|
+
const items = (pricedItems ?? []).filter((item) => deps.pricing.view(item.reference).route === "appleIap");
|
|
2545
|
+
return items.length ? opened.checkAccess(items.map((item) => ({ reference: item.reference }))) : Promise.resolve(state());
|
|
2546
|
+
}
|
|
2547
|
+
function state() {
|
|
2548
|
+
return checkout?.state() ?? notEnabledState();
|
|
2549
|
+
}
|
|
2550
|
+
return {
|
|
2551
|
+
pricing: deps.pricing,
|
|
2552
|
+
loadPrices,
|
|
2553
|
+
readiness: () => readiness,
|
|
2554
|
+
scopeComplete: () => lastScopeComplete,
|
|
2555
|
+
state,
|
|
2556
|
+
purchaseFields,
|
|
2557
|
+
start,
|
|
2558
|
+
buy,
|
|
2559
|
+
reconcile: reconcile2,
|
|
2560
|
+
tick: () => checkout ? checkout.tick() : Promise.resolve(state()),
|
|
2561
|
+
pollDirective,
|
|
2562
|
+
poll,
|
|
2563
|
+
dispose: () => {
|
|
2564
|
+
disposed = true;
|
|
2565
|
+
stopWatchingSession?.();
|
|
2566
|
+
stopWatchingAccess?.();
|
|
2567
|
+
deps.pricing.dispose();
|
|
2568
|
+
checkout?.dispose();
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2572
|
+
var POLL_ID2 = "iapCommerce";
|
|
2573
|
+
var PRICE_REFRESH_MS = 6e4;
|
|
2574
|
+
var PRICE_REFRESH_SLACK_MS = 1e4;
|
|
2575
|
+
var DUE_WORK_POLL_MS = 2e3;
|
|
2576
|
+
var SUSPENDED_AFTER_MS = 2 * PRICE_REFRESH_MS;
|
|
2577
|
+
function unanswered2(view) {
|
|
2578
|
+
return view.route === "resolving" || view.reason === "mappingUnavailable";
|
|
2579
|
+
}
|
|
2580
|
+
function hostFor(identity, binding) {
|
|
2581
|
+
if (binding.himalayaAppId !== identity.appId || binding.bundleId !== identity.bundleId) return null;
|
|
2582
|
+
return { appId: identity.appId, bundleId: identity.bundleId, siteId: binding.siteId };
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
// ../../stdlib/flows/iap-checkout/src/commerce.ts
|
|
2586
|
+
function createIapCommerce(options = {}) {
|
|
2587
|
+
const session = hostSessionFromGlobal();
|
|
2588
|
+
const identity = memberIdentityOf(session);
|
|
2589
|
+
const binding = sharedHostAppBindingSource();
|
|
2590
|
+
return createIapCommerceWith({
|
|
2591
|
+
routes: appleIapCheckoutRoutes(),
|
|
2592
|
+
pricing: createIapCatalogPricing({ onChange: options.onChange }),
|
|
2593
|
+
binding,
|
|
2594
|
+
session,
|
|
2595
|
+
host: hostOfWorker(),
|
|
2596
|
+
store: appleManagedStore,
|
|
2597
|
+
refs: createWorkerOrderRefStore(),
|
|
2598
|
+
clock: { now: () => Date.now() },
|
|
2599
|
+
adapters: options.adapters ?? [],
|
|
2600
|
+
identity,
|
|
2601
|
+
wixIapClient: ({ host, route }) => createWixIapClient({ session, binding, identity, host, route }),
|
|
2602
|
+
onChange: options.onChange
|
|
2603
|
+
});
|
|
2604
|
+
}
|
|
2605
|
+
function hostOfWorker() {
|
|
2606
|
+
let read2;
|
|
2607
|
+
return {
|
|
2608
|
+
identity: () => read2 ?? (read2 = readIdentity().then((identity) => {
|
|
2609
|
+
if (!identity) read2 = void 0;
|
|
2610
|
+
return identity;
|
|
2611
|
+
})),
|
|
2612
|
+
preferenceSite
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
async function readIdentity() {
|
|
2616
|
+
const info = await get().catch(() => void 0);
|
|
2617
|
+
return info?.appId && info.bundleId && info.platform ? { appId: info.appId, bundleId: info.bundleId, platform: info.platform } : null;
|
|
2618
|
+
}
|
|
2619
|
+
function preferenceSite() {
|
|
2620
|
+
const value = globalThis.himalaya?.input?.__himiPreferenceBusiness;
|
|
2621
|
+
return typeof value === "string" ? value.trim() : "";
|
|
2622
|
+
}
|
|
2623
|
+
|
|
1502
2624
|
// ../../stdlib/flows/iap-checkout/src/apple-iap.ts
|
|
1503
2625
|
function createAppleIapCheckout(deps) {
|
|
1504
2626
|
return createAppleIapCheckoutWith({ ...deps, enabled: appleIapCheckoutEnabled() });
|
|
@@ -1527,9 +2649,9 @@ function isHttp(outcome, httpStatus) {
|
|
|
1527
2649
|
}
|
|
1528
2650
|
function bodyObject(outcome, name) {
|
|
1529
2651
|
const body = outcome.body;
|
|
1530
|
-
return
|
|
2652
|
+
return isObject7(body) && isObject7(body[name]) ? body[name] : null;
|
|
1531
2653
|
}
|
|
1532
|
-
function
|
|
2654
|
+
function isObject7(value) {
|
|
1533
2655
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1534
2656
|
}
|
|
1535
2657
|
function isNonEmpty3(value) {
|
|
@@ -1548,20 +2670,21 @@ var onlineProgramOrders = {
|
|
|
1548
2670
|
eligibility: (item) => singleUnitOf(KIND, item),
|
|
1549
2671
|
openOrder,
|
|
1550
2672
|
reopenOrder,
|
|
1551
|
-
readAccess
|
|
2673
|
+
readAccess,
|
|
2674
|
+
currentAccess
|
|
1552
2675
|
};
|
|
1553
2676
|
async function openOrder(item, bridge) {
|
|
1554
2677
|
const found = await currentApplication(item.reference.id, bridge);
|
|
1555
2678
|
if ("attempt" in found) return found.attempt;
|
|
1556
|
-
const
|
|
1557
|
-
if ("attempt" in
|
|
1558
|
-
return orderOf(
|
|
2679
|
+
const read2 = found.application ? { application: found.application } : await createdApplication(item.reference.id, bridge);
|
|
2680
|
+
if ("attempt" in read2) return read2.attempt;
|
|
2681
|
+
return orderOf(read2.application, bridge, { mayPrepare: true });
|
|
1559
2682
|
}
|
|
1560
2683
|
async function reopenOrder(order, bridge) {
|
|
1561
|
-
const
|
|
1562
|
-
if ("attempt" in
|
|
1563
|
-
const
|
|
1564
|
-
return
|
|
2684
|
+
const read2 = await applicationById(order.verticalRef.joinApplicationId, bridge);
|
|
2685
|
+
if ("attempt" in read2) return read2.attempt;
|
|
2686
|
+
const attempt3 = await orderOf(read2.application, bridge, { mayPrepare: false });
|
|
2687
|
+
return attempt3.status === "open" && attempt3.cashierOrderId !== order.cashierOrderId ? ORDER_CLOSED : attempt3;
|
|
1565
2688
|
}
|
|
1566
2689
|
async function readAccess(verticalRef, bridge) {
|
|
1567
2690
|
if (!isNonEmpty3(verticalRef.joinApplicationId)) return "unavailable";
|
|
@@ -1570,6 +2693,14 @@ async function readAccess(verticalRef, bridge) {
|
|
|
1570
2693
|
const application = bodyObject(answer, "joinApplication");
|
|
1571
2694
|
return application ? accessOf(application) : "unavailable";
|
|
1572
2695
|
}
|
|
2696
|
+
async function currentAccess(item, bridge) {
|
|
2697
|
+
const answer = await bridge.call("GET", `${BASE}/current/${encodeURIComponent(item.reference.id)}`);
|
|
2698
|
+
if (isRefusal(answer)) return accessRefused(answer);
|
|
2699
|
+
const application = bodyObject(answer, "joinApplication");
|
|
2700
|
+
if (!application) return "unavailable";
|
|
2701
|
+
const access = accessOf(application);
|
|
2702
|
+
return access !== "granted" && ENDED_STATUS.has(String(application.status)) ? "none" : access;
|
|
2703
|
+
}
|
|
1573
2704
|
function accessOf(application) {
|
|
1574
2705
|
const paid = application.paymentStatus === "PAYMENT_SUCCESSFUL" || application.paymentStatus === "NO_PAYMENT_REQUIRED";
|
|
1575
2706
|
if (application.status === "APPROVED" && paid && isNonEmpty3(application.participantId)) return "granted";
|
|
@@ -1602,8 +2733,8 @@ async function preparedOrder(application, bridge) {
|
|
|
1602
2733
|
return prepared ? orderOf(prepared, bridge, { mayPrepare: false }) : ORDER_REFUSED;
|
|
1603
2734
|
}
|
|
1604
2735
|
async function reopenAfterRace(id, bridge) {
|
|
1605
|
-
const
|
|
1606
|
-
return "attempt" in
|
|
2736
|
+
const read2 = await applicationById(id, bridge);
|
|
2737
|
+
return "attempt" in read2 ? read2.attempt : orderOf(read2.application, bridge, { mayPrepare: false });
|
|
1607
2738
|
}
|
|
1608
2739
|
async function currentApplication(programId, bridge) {
|
|
1609
2740
|
const answer = await bridge.call("GET", `${BASE}/current/${encodeURIComponent(programId)}`);
|
|
@@ -1636,6 +2767,7 @@ function applicationIn(answer) {
|
|
|
1636
2767
|
var PREPARABLE = /* @__PURE__ */ new Set(["PAYMENT_PENDING", "PAYMENT_FAILED", "PAYMENT_CANCELED"]);
|
|
1637
2768
|
var PAYMENT_UNDER_WAY = /* @__PURE__ */ new Set(["PAYMENT_PENDING", "PAYMENT_IN_PROGRESS", "PENDING_OWNER_APPROVAL"]);
|
|
1638
2769
|
var NO_ACCESS_STATUS = /* @__PURE__ */ new Set(["CANCELLED", "DECLINED", "SUSPENDED", "INVITED", "APPROVAL_PENDING"]);
|
|
2770
|
+
var ENDED_STATUS = /* @__PURE__ */ new Set(["CANCELLED", "DECLINED", "SUSPENDED"]);
|
|
1639
2771
|
var NO_ACCESS_PAYMENT = /* @__PURE__ */ new Set(["PAYMENT_FAILED", "PAYMENT_CANCELED"]);
|
|
1640
2772
|
|
|
1641
2773
|
// ../../stdlib/flows/iap-checkout/src/iap-verticals/pricing-plans.ts
|
|
@@ -1659,10 +2791,10 @@ async function openOrder2(item, bridge) {
|
|
|
1659
2791
|
return orderOf2(bodyObject(created, "order"), planId);
|
|
1660
2792
|
}
|
|
1661
2793
|
async function reopenOrder2(order, bridge) {
|
|
1662
|
-
const
|
|
1663
|
-
if ("attempt" in
|
|
1664
|
-
const
|
|
1665
|
-
return
|
|
2794
|
+
const read2 = await memberOrder(order.verticalRef.orderId, bridge);
|
|
2795
|
+
if ("attempt" in read2) return read2.attempt;
|
|
2796
|
+
const attempt3 = orderOf2(read2.order, order.verticalRef.planId ?? "");
|
|
2797
|
+
return attempt3.status === "open" && attempt3.cashierOrderId !== order.cashierOrderId ? ORDER_CLOSED : attempt3;
|
|
1666
2798
|
}
|
|
1667
2799
|
async function readAccess2(verticalRef, bridge) {
|
|
1668
2800
|
if (!isNonEmpty3(verticalRef.orderId)) return "unavailable";
|
|
@@ -1743,7 +2875,7 @@ async function readAccess3(verticalRef, bridge) {
|
|
|
1743
2875
|
return NO_ACCESS2.has(status) ? "none" : "unavailable";
|
|
1744
2876
|
}
|
|
1745
2877
|
async function placedOrder(body, bridge) {
|
|
1746
|
-
if (!
|
|
2878
|
+
if (!isObject7(body) || !isNonEmpty3(body.orderId)) return ORDER_REFUSED;
|
|
1747
2879
|
const verticalRef = { orderId: body.orderId };
|
|
1748
2880
|
if (isNonEmpty3(body.paymentGatewayOrderId)) return { status: "open", cashierOrderId: body.paymentGatewayOrderId, verticalRef };
|
|
1749
2881
|
const access = await readAccess3(verticalRef, bridge);
|
|
@@ -1755,7 +2887,9 @@ var NO_ACCESS2 = /* @__PURE__ */ new Set(["FULLY_REFUNDED", "PARTIALLY_REFUNDED"
|
|
|
1755
2887
|
export {
|
|
1756
2888
|
classifyCart,
|
|
1757
2889
|
createAppleIapCheckout,
|
|
2890
|
+
createIapCommerce,
|
|
1758
2891
|
createWorkerOrderRefStore,
|
|
2892
|
+
iapPurchaseFields,
|
|
1759
2893
|
onlineProgramOrders,
|
|
1760
2894
|
pricingPlanOrders,
|
|
1761
2895
|
storesProductOrders
|