@wix/himalaya-cli 0.1368.0 → 0.1369.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/mapping-source.d.ts +3 -1
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-contract.d.ts +44 -2
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-wire.d.ts +14 -1
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments.d.ts +9 -3
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +18 -5
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-core.d.ts +2 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/checkout-source.d.ts +8 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-core.d.ts +2 -0
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-order-backend.d.ts +3 -0
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/index.d.ts +1 -0
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/order-refs.d.ts +5 -1
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +167 -41
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +75 -21
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +147 -30
  15. package/dist/cli.mjs +7 -6
  16. package/guides/iap-screen-adoption.md +3 -2
  17. package/guides/sdk-reference.json +57 -9
  18. package/package.json +2 -2
  19. package/templates/beauty-salon/dev/index.ts +49 -1
  20. package/templates/beauty-salon/tier5-src/_shared/iap-presentation.ts +4 -2
  21. package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +68 -5
  22. package/templates/branded-lite/dev/index.ts +49 -1
  23. package/templates/branded-lite/tier5-src/_shared/iap-presentation.ts +4 -2
  24. package/templates/branded-lite/tier5-src/himi-store-product/index.ts +68 -5
  25. package/templates/community-club/tier5-src/_shared/iap-presentation.ts +4 -2
  26. package/templates/events-meetups/tier5-src/_shared/iap-presentation.ts +4 -2
  27. package/templates/gym-fitness/dev/index.ts +49 -1
  28. package/templates/gym-fitness/tier5-src/_shared/iap-presentation.ts +4 -2
  29. package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +68 -5
  30. package/templates/nonprofit-cause/tier5-src/_shared/iap-presentation.ts +4 -2
  31. package/templates/podcast-creator/tier5-src/_shared/iap-presentation.ts +4 -2
  32. package/templates/portfolio-creative/dev/index.ts +49 -1
  33. package/templates/portfolio-creative/tier5-src/_shared/iap-presentation.ts +4 -2
  34. package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +68 -5
  35. package/templates/restaurant/tier5-src/_shared/iap-presentation.ts +4 -2
  36. package/templates/retail-store/dev/index.ts +49 -1
  37. package/templates/retail-store/tier5-src/_shared/iap-presentation.ts +4 -2
  38. package/templates/retail-store/tier5-src/himi-store-product/index.ts +68 -5
  39. package/templates/yoga-studio/tier5-src/_shared/iap-presentation.ts +4 -2
@@ -685,15 +685,18 @@ var sameReference = (value, reference) => isObject2(value) && value.kind === ref
685
685
 
686
686
  // ../../core/sdk/iap/src/wix-payments-contract.ts
687
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
- };
688
+ var STORES_ITEM_PAYMENT_ENABLED = false;
689
+ var STORES_PRODUCT_SALE_RULE = { appProductId: (id) => id, productType: "NON_CONSUMABLE" };
690
+ var ONLINE_PROGRAM_SALE_RULE = { appProductId: (id) => id, productType: "NON_CONSUMABLE" };
691
+ var APPLE_SALE_RULES = STORES_ITEM_PAYMENT_ENABLED ? { onlineProgram: ONLINE_PROGRAM_SALE_RULE, storesProduct: STORES_PRODUCT_SALE_RULE } : { onlineProgram: ONLINE_PROGRAM_SALE_RULE };
691
692
 
692
693
  // ../../core/sdk/iap/src/mapping-source.ts
693
694
  function iapMappingSource() {
694
695
  return createWixIapMappingSource({ binding: sharedHostAppBindingSource(), call: hostWixCall });
695
696
  }
696
697
  function createWixIapMappingSource(deps) {
698
+ const rules = deps.rules ?? APPLE_SALE_RULES;
699
+ const appProductIdOf = (reference) => reference.id ? rules[reference.kind]?.appProductId(reference.id) : void 0;
697
700
  return {
698
701
  // Only a binding the host actually returned: a read that failed is re-asked on the next load.
699
702
  active: async () => await deps.binding.current() !== null,
@@ -704,14 +707,11 @@ function createWixIapMappingSource(deps) {
704
707
  if (scope.siteId && !sameId(scope.siteId, binding.siteId)) return references.map((reference) => ({ reference, route: "unavailable" }));
705
708
  const asked = [...new Set(references.flatMap((reference) => appProductIdOf(reference) ?? []))];
706
709
  const mapped = await resolveAll(deps.call, binding, asked);
707
- return references.map((reference) => decide(reference, binding, mapped));
710
+ return references.map((reference) => decide(reference, binding, mapped.get(appProductIdOf(reference) ?? ""), rules[reference.kind]));
708
711
  }
709
712
  }
710
713
  };
711
714
  }
712
- function appProductIdOf(reference) {
713
- return reference.id ? APPLE_SALE_RULES[reference.kind]?.appProductId(reference.id) : void 0;
714
- }
715
715
  var PATH = `${HIMALAYA_SERVE_IAP_ROUTE.prefix}/mappings`;
716
716
  var BATCH = 100;
717
717
  async function resolveAll(call, binding, ids) {
@@ -735,11 +735,9 @@ function decodeMappings(reply) {
735
735
  return [m.appProductId, { storeProductId: m.storeProductId, type: String(m.type ?? ""), active: m.active === true }];
736
736
  });
737
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" };
738
+ function decide(reference, binding, mapping, rule) {
739
+ if (!mapping || !rule) return { reference, route: "regular" };
740
+ if (!mapping.active || mapping.type !== rule.productType) return { reference, route: "unavailable" };
743
741
  return { reference, route: "appleIap", productId: mapping.storeProductId, mappingRevision: `${binding.purchasesAppId}:${mapping.storeProductId}` };
744
742
  }
745
743
  function sameId(a, b) {
@@ -1012,6 +1010,15 @@ function wixApiGlobal() {
1012
1010
  function startPaymentCall(scope, wixTransactionId) {
1013
1011
  return post(scope, "/payments/start", { appId: scope.binding.purchasesAppId, wixTransactionId });
1014
1012
  }
1013
+ function startItemPaymentCall(scope, item) {
1014
+ return post(scope, "/payments/start-item", { appId: scope.binding.purchasesAppId, item: { catalogItemId: item.catalogItemId, catalogAppId: item.catalogAppId } });
1015
+ }
1016
+ function catalogItemOf(raw) {
1017
+ const item = isObject3(raw) ? raw : {};
1018
+ const { catalogItemId, catalogAppId } = item;
1019
+ const valid = typeof catalogItemId === "string" && catalogItemId.length > 0 && catalogItemId.length <= 36 && isUUID(catalogAppId);
1020
+ return valid ? { catalogItemId, catalogAppId } : null;
1021
+ }
1015
1022
  function completePaymentCall(scope, signedTransaction) {
1016
1023
  return post(scope, "/payments/complete", { appId: scope.binding.purchasesAppId, apple: { signedTransaction } });
1017
1024
  }
@@ -1026,6 +1033,12 @@ function decodeStarted(raw, expected) {
1026
1033
  const payment = decodePayment(raw.payment, expected);
1027
1034
  return payment && { payment, storeProductId: raw.storeProductId, appAccountToken: raw.appAccountToken };
1028
1035
  }
1036
+ function decodeStartedItem(raw, expected) {
1037
+ if (!isObject3(raw) || !isUUID(raw.ecomOrderId)) return null;
1038
+ const started = decodeStarted(raw, expected);
1039
+ if (!started || started.payment.appProductId !== expected.catalogItemId) return null;
1040
+ return { ...started, ecomOrderId: raw.ecomOrderId };
1041
+ }
1029
1042
  function decodePaymentAnswer(raw, expected) {
1030
1043
  return isObject3(raw) ? decodePayment(raw.payment, expected) : null;
1031
1044
  }
@@ -1148,6 +1161,19 @@ function createWixIapClient(deps) {
1148
1161
  }
1149
1162
  });
1150
1163
  }
1164
+ function startItemPayment(input) {
1165
+ const item = catalogItemOf(input.item);
1166
+ if (!item) return Promise.resolve(failure("startItemPayment", "invalidArgument"));
1167
+ return runUnrepeatable({
1168
+ operation: "startItemPayment",
1169
+ codes: START_ITEM_PAYMENT_CODES,
1170
+ request: (scope) => startItemPaymentCall(scope, item),
1171
+ decode: (raw, scope) => {
1172
+ const started = decodeStartedItem(raw, { ...expectationOf2(scope), catalogItemId: item.catalogItemId });
1173
+ return started && { status: "started", ...started };
1174
+ }
1175
+ });
1176
+ }
1151
1177
  function completePayment(transaction) {
1152
1178
  const refusal = refuseProof(transaction);
1153
1179
  if (refusal) return Promise.resolve(refusal);
@@ -1174,11 +1200,18 @@ function createWixIapClient(deps) {
1174
1200
  });
1175
1201
  }
1176
1202
  async function run(spec) {
1203
+ return (await execute(spec)).result;
1204
+ }
1205
+ async function runUnrepeatable(spec) {
1206
+ const { result, handedOff } = await execute(spec);
1207
+ return handedOff && isUndecided(result) ? outcomeUnknown(result) : result;
1208
+ }
1209
+ async function execute(spec) {
1177
1210
  const scope = await resolveScope(deps.session.current(), spec.operation);
1178
- if ("failure" in scope) return scope.failure;
1211
+ if ("failure" in scope) return { result: scope.failure, handedOff: false };
1179
1212
  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");
1213
+ if ("failure" in sent) return { result: sent.failure, handedOff: sent.handedOff };
1214
+ return { result: spec.decode(sent.answer, scope) ?? failure(spec.operation, "invalidResponse"), handedOff: true };
1182
1215
  }
1183
1216
  async function resolveScope(session, operation) {
1184
1217
  if (session.kind !== "member") return refused(operation, "authRequired");
@@ -1199,12 +1232,12 @@ function createWixIapClient(deps) {
1199
1232
  }
1200
1233
  async function send(scope, spec) {
1201
1234
  const transport = deps.transport ?? bridgeTransport();
1202
- if (!transport) return refused(spec.operation, "notEnabled");
1203
- if (!isCurrent(scope.session)) return refused(spec.operation, "sessionChanged");
1235
+ if (!transport) return notSent(spec.operation, "notEnabled");
1236
+ if (!isCurrent(scope.session)) return notSent(spec.operation, "sessionChanged");
1204
1237
  const expectation = boundExpectation2(scope.session, deps.transport == null);
1205
- if (expectation === "refuse") return refused(spec.operation, "notEnabled");
1238
+ if (expectation === "refuse") return notSent(spec.operation, "notEnabled");
1206
1239
  const outcome = await attempt(transport, spec.request(scope), spec, expectation);
1207
- return isCurrent(scope.session) ? outcome : refused(spec.operation, "sessionChanged");
1240
+ return isCurrent(scope.session) ? outcome : { failure: failure(spec.operation, "sessionChanged"), handedOff: true };
1208
1241
  }
1209
1242
  function boundExpectation2(session, liveHost) {
1210
1243
  const source = deps.session;
@@ -1215,16 +1248,27 @@ function createWixIapClient(deps) {
1215
1248
  function isCurrent(session) {
1216
1249
  return deps.session.current().generation === session.generation;
1217
1250
  }
1218
- return { startPayment, completePayment, getPayment };
1251
+ return { startPayment, startItemPayment, completePayment, getPayment };
1219
1252
  }
1220
1253
  async function attempt(transport, call, spec, expectation) {
1221
1254
  try {
1222
1255
  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
1256
  return { answer };
1224
1257
  } catch (error) {
1225
- return { failure: classifyFailure(error, spec.operation, spec.codes) };
1258
+ return { failure: classifyFailure(error, spec.operation, spec.codes), handedOff: true };
1226
1259
  }
1227
1260
  }
1261
+ function notSent(operation, kind) {
1262
+ return { failure: failure(operation, kind), handedOff: false };
1263
+ }
1264
+ function isUndecided(result) {
1265
+ const failed = result;
1266
+ return failed.status === "failed" && UNDECIDED.has(failed.kind);
1267
+ }
1268
+ function outcomeUnknown(failed) {
1269
+ const status = failed.httpStatus === void 0 ? {} : { httpStatus: failed.httpStatus };
1270
+ return { status: "outcomeUnknown", operation: "startItemPayment", kind: failed.kind, ...status };
1271
+ }
1228
1272
  async function read(call, operation) {
1229
1273
  try {
1230
1274
  return { value: await call() };
@@ -1260,6 +1304,14 @@ var START_PAYMENT_CODES = [
1260
1304
  "PRODUCT_NOT_AVAILABLE",
1261
1305
  "ALREADY_OWNED"
1262
1306
  ];
1307
+ var START_ITEM_PAYMENT_CODES = [
1308
+ "PRODUCT_NOT_AVAILABLE",
1309
+ "ALREADY_OWNED",
1310
+ "ITEM_NOT_AVAILABLE",
1311
+ "SITE_NOT_ACCEPTING_PAYMENTS",
1312
+ "UNSUPPORTED_ORDER"
1313
+ ];
1314
+ var UNDECIDED = /* @__PURE__ */ new Set(["unavailable", "sessionChanged", "invalidResponse"]);
1263
1315
  var COMPLETE_PAYMENT_CODES = [
1264
1316
  "INVALID_PURCHASE",
1265
1317
  "OWNED_BY_ANOTHER_CUSTOMER",
@@ -1377,6 +1429,9 @@ function appleIapCheckoutRoutes() {
1377
1429
  function appleIapCheckoutEnabled() {
1378
1430
  return appleIapCheckoutRoutes() !== null;
1379
1431
  }
1432
+ function itemPaymentEnabled() {
1433
+ return STORES_ITEM_PAYMENT_ENABLED;
1434
+ }
1380
1435
 
1381
1436
  // ../../stdlib/flows/iap-checkout/src/cashier-charges.ts
1382
1437
  async function ensureAppleIapCharge(bridge, route, orderId) {
@@ -1473,8 +1528,9 @@ function isFinalRefusal(status) {
1473
1528
 
1474
1529
  // ../../stdlib/flows/iap-checkout/src/order-refs.ts
1475
1530
  var NEEDS_SUPPORT_HOLD_MS = 6048e5;
1531
+ var ITEM_START_HOLD_MS = 36e5;
1476
1532
  function pruneExpiredHolds(partition, now) {
1477
- const expired = partition.refs().filter((ref) => HOLDS.has(ref.stage) && now - ref.updatedAt >= NEEDS_SUPPORT_HOLD_MS);
1533
+ const expired = partition.refs().filter((ref) => now - ref.updatedAt >= (HOLD_MS[ref.stage] ?? Infinity));
1478
1534
  return expired.filter((ref) => partition.remove(ref.key)).map((ref) => ref.key);
1479
1535
  }
1480
1536
  var MAX_ORDER_REFS = 16;
@@ -1607,8 +1663,8 @@ function isUUID3(value) {
1607
1663
  }
1608
1664
  var VERSION = 1;
1609
1665
  var PREFIX = "himi.iap.wix-checkout.v1";
1610
- var STAGES = /* @__PURE__ */ new Set(["ordered", "charged", "started", "submitted", "held", "needsSupport"]);
1611
- var HOLDS = /* @__PURE__ */ new Set(["held", "needsSupport"]);
1666
+ var STAGES = /* @__PURE__ */ new Set(["startingItem", "ordered", "charged", "started", "submitted", "held", "needsSupport"]);
1667
+ var HOLD_MS = { held: NEEDS_SUPPORT_HOLD_MS, needsSupport: NEEDS_SUPPORT_HOLD_MS, startingItem: ITEM_START_HOLD_MS };
1612
1668
  var EVICTABLE = /* @__PURE__ */ new Set(["ordered", "charged", "started"]);
1613
1669
 
1614
1670
  // ../../stdlib/flows/iap-checkout/src/wix-bridge.ts
@@ -1693,18 +1749,30 @@ function createWixOrderBackend(deps) {
1693
1749
  async function getPurchaseContext(session, catalogRef) {
1694
1750
  const sale = await saleFor(session, catalogRef);
1695
1751
  if (isStop(sale)) return contextResult(catalogRef, sale);
1752
+ const blocked = saleBlocked(sale);
1753
+ if (blocked) return contextResult(catalogRef, blocked);
1754
+ const itemPayment2 = deps.itemPaymentEnabled ? sale.adapter.itemPayment?.(sale.item) : null;
1755
+ return itemPayment2 ? startItemFor(sale, itemPayment2) : startOrderFor(sale);
1756
+ }
1757
+ async function startOrderFor(sale) {
1696
1758
  const ordered = await orderFor(sale);
1697
- if (isStop(ordered)) return contextResult(catalogRef, ordered);
1759
+ if (isStop(ordered)) return contextResult(sale.catalogRef, ordered);
1698
1760
  const charged = await chargeFor(sale, ordered, { reordered: false });
1699
- if (isStop(charged)) return contextResult(catalogRef, charged);
1761
+ if (isStop(charged)) return contextResult(sale.catalogRef, charged);
1700
1762
  return startFor(sale, charged);
1701
1763
  }
1764
+ function saleBlocked(sale) {
1765
+ const stage = refAt(sale.partition, sale.catalogRef)?.stage;
1766
+ const failure3 = stage && BLOCKING_STAGES[stage];
1767
+ if (failure3) return stopWith("rejected", failure3);
1768
+ return deps.productBusy?.(sale.appleProduct.productId) ? stopWith("rejected", "paymentInProgress") : null;
1769
+ }
1702
1770
  async function saleFor(session, catalogRef) {
1703
1771
  const sold = deps.itemFor(catalogRef);
1704
1772
  const adapter = sold && adapterFor(sold.item.reference.kind);
1705
1773
  if (!sold || !adapter) return stopWith("rejected", "unsupportedItem");
1706
- const eligibility = adapter.eligibility(sold.item);
1707
- if (!eligibility.eligible) return stopWith("rejected", eligibility.reason);
1774
+ const eligibility2 = adapter.eligibility(sold.item);
1775
+ if (!eligibility2.eligible) return stopWith("rejected", eligibility2.reason);
1708
1776
  const member = await memberOf(session);
1709
1777
  if (isStop(member)) return member;
1710
1778
  if (!member.partition) return stopWith("rejected", "storageUnavailable");
@@ -1722,10 +1790,6 @@ function createWixOrderBackend(deps) {
1722
1790
  }
1723
1791
  async function orderFor(sale) {
1724
1792
  const existing = refAt(sale.partition, sale.catalogRef);
1725
- if (existing?.stage === "submitted") return stopWith("rejected", "paymentInProgress");
1726
- if (existing?.stage === "held") return stopWith("rejected", "paymentHeld");
1727
- if (existing?.stage === "needsSupport") return stopWith("rejected", "needsSupport");
1728
- if (deps.productBusy?.(sale.appleProduct.productId)) return stopWith("rejected", "paymentInProgress");
1729
1793
  const attempt3 = existing?.cashierOrderId && existing.verticalRef ? await reopenOrOpen(sale, { cashierOrderId: existing.cashierOrderId, verticalRef: existing.verticalRef }) : await sale.adapter.openOrder(sale.item, sale.bridge);
1730
1794
  return recordOrder(sale, existing, attempt3);
1731
1795
  }
@@ -1801,6 +1865,40 @@ function createWixOrderBackend(deps) {
1801
1865
  if (isStop(recorded)) return contextResult(sale.catalogRef, recorded);
1802
1866
  return { status: "ok", context: { productId: started.storeProductId, appAccountToken: started.appAccountToken, scopeKey: sale.member.scopeKey } };
1803
1867
  }
1868
+ async function startItemFor(sale, itemPayment2) {
1869
+ const attempt3 = persist(sale, { key: sale.catalogRef, stage: "startingItem", kind: sale.adapter.kind, storeProductId: sale.appleProduct.productId, updatedAt: now() });
1870
+ if (isStop(attempt3)) return contextResult(sale.catalogRef, attempt3);
1871
+ const started = await deps.wixIap.startItemPayment({ item: itemPayment2.catalogItem });
1872
+ if (started.status === "outcomeUnknown") return contextResult(sale.catalogRef, sale.bridge.isCurrent() ? OUTCOME_UNKNOWN : STALE2);
1873
+ if (started.status !== "started") return contextResult(sale.catalogRef, itemRefusal(sale, started));
1874
+ return startedItem(sale, itemPayment2, started);
1875
+ }
1876
+ function startedItem(sale, itemPayment2, started) {
1877
+ if (started.storeProductId !== sale.appleProduct.productId) return contextResult(sale.catalogRef, stopWith("rejected", "productChanged"));
1878
+ const { payment, storeProductId, appAccountToken } = started;
1879
+ const recorded = persist(sale, {
1880
+ key: sale.catalogRef,
1881
+ stage: "started",
1882
+ kind: sale.adapter.kind,
1883
+ verticalRef: itemPayment2.verticalRefOf(started.ecomOrderId),
1884
+ wixTransactionId: payment.wixTransactionId,
1885
+ paymentId: payment.paymentId,
1886
+ storeProductId,
1887
+ appAccountToken: appAccountToken.toLowerCase(),
1888
+ ...payment.appProductId ? { appProductId: payment.appProductId } : {},
1889
+ updatedAt: now()
1890
+ });
1891
+ if (isStop(recorded)) return contextResult(sale.catalogRef, recorded);
1892
+ return { status: "ok", context: { productId: storeProductId, appAccountToken, scopeKey: sale.member.scopeKey } };
1893
+ }
1894
+ function itemRefusal(sale, failure3) {
1895
+ if (failure3.kind === "application") return undoAttempt(sale, stopWith("rejected", ITEM_REFUSALS[failure3.code]));
1896
+ return undoAttempt(sale, failure3.kind === "unrecognized" ? NOT_CONFIGURED : failureStop(failure3));
1897
+ }
1898
+ function undoAttempt(sale, stop) {
1899
+ sale.partition.remove(sale.catalogRef);
1900
+ return stop;
1901
+ }
1804
1902
  function startedMismatch(sale, started) {
1805
1903
  return sale.appleProduct.productId === started.storeProductId ? null : "productChanged";
1806
1904
  }
@@ -1925,6 +2023,20 @@ function failureStop(failure3) {
1925
2023
  var SIGN_IN = { stop: true, result: "authRequired", failure: "signInRequired" };
1926
2024
  var NOT_CONFIGURED = { stop: true, result: "rejected", failure: "notConfigured" };
1927
2025
  var UNAVAILABLE = { stop: true, result: "retryable", failure: "unavailable" };
2026
+ var OUTCOME_UNKNOWN = { stop: true, result: "rejected", failure: "outcomeUnknown" };
2027
+ var BLOCKING_STAGES = {
2028
+ startingItem: "outcomeUnknown",
2029
+ submitted: "paymentInProgress",
2030
+ held: "paymentHeld",
2031
+ needsSupport: "needsSupport"
2032
+ };
2033
+ var ITEM_REFUSALS = {
2034
+ PRODUCT_NOT_AVAILABLE: "paymentRefused",
2035
+ ALREADY_OWNED: "paymentRefused",
2036
+ ITEM_NOT_AVAILABLE: "orderRefused",
2037
+ SITE_NOT_ACCEPTING_PAYMENTS: "orderRefused",
2038
+ UNSUPPORTED_ORDER: "orderRefused"
2039
+ };
1928
2040
  var KIND_STOPS = {
1929
2041
  authRequired: SIGN_IN,
1930
2042
  notPermitted: SIGN_IN,
@@ -2006,6 +2118,7 @@ function enabledCheckout(deps) {
2006
2118
  bridge,
2007
2119
  itemFor: (key) => sales.get(key),
2008
2120
  productBusy,
2121
+ itemPaymentEnabled: deps.itemPaymentEnabled,
2009
2122
  report: onEvent
2010
2123
  });
2011
2124
  const coordinator = createPurchaseCoordinator({
@@ -2369,6 +2482,8 @@ var REFUSALS = {
2369
2482
  paymentHeld: ["disabled", "support"],
2370
2483
  needsSupport: ["disabled", "support"],
2371
2484
  invalidAssociation: ["disabled", "support"],
2485
+ // An order may exist for a StartItemPayment whose answer was lost: no second tap until it expires.
2486
+ outcomeUnknown: ["disabled", "support"],
2372
2487
  // Nothing in the checkout clears this, so the action stays tappable: a tap re-reads the order
2373
2488
  // (never a second charge) and turns into access once the vertical grants it.
2374
2489
  paymentInProgress: ["enabled", "processing"],
@@ -2469,6 +2584,7 @@ function createIapCommerceWith(deps) {
2469
2584
  stopWatchingSession = void 0;
2470
2585
  checkout = createAppleIapCheckoutWith({
2471
2586
  enabled: true,
2587
+ itemPaymentEnabled: deps.itemPaymentEnabled,
2472
2588
  wixIap: deps.wixIapClient({ host, route: routes.wixIap }),
2473
2589
  binding: deps.binding,
2474
2590
  session: deps.session,
@@ -2589,6 +2705,7 @@ function createIapCommerce(options = {}) {
2589
2705
  const binding = sharedHostAppBindingSource();
2590
2706
  return createIapCommerceWith({
2591
2707
  routes: appleIapCheckoutRoutes(),
2708
+ itemPaymentEnabled: itemPaymentEnabled(),
2592
2709
  pricing: createIapCatalogPricing({ onChange: options.onChange }),
2593
2710
  binding,
2594
2711
  session,
@@ -2623,7 +2740,7 @@ function preferenceSite() {
2623
2740
 
2624
2741
  // ../../stdlib/flows/iap-checkout/src/apple-iap.ts
2625
2742
  function createAppleIapCheckout(deps) {
2626
- return createAppleIapCheckoutWith({ ...deps, enabled: appleIapCheckoutEnabled() });
2743
+ return createAppleIapCheckoutWith({ ...deps, enabled: appleIapCheckoutEnabled(), itemPaymentEnabled: itemPaymentEnabled() });
2627
2744
  }
2628
2745
 
2629
2746
  // ../../stdlib/flows/iap-checkout/src/iap-verticals/shared.ts
@@ -2849,19 +2966,27 @@ function isOneTimeUnlimited(order) {
2849
2966
 
2850
2967
  // ../../stdlib/flows/iap-checkout/src/iap-verticals/stores.ts
2851
2968
  var KIND3 = "storesProduct";
2969
+ var WIX_STORES_APP = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
2852
2970
  var storesProductOrders = {
2853
2971
  kind: KIND3,
2854
- eligibility: (item) => {
2855
- const single = singleUnitOf(KIND3, item);
2856
- if (!single.eligible) return single;
2857
- const catalog = item.catalogReference;
2858
- const variant = catalog?.options && Object.keys(catalog.options).length > 0;
2859
- return catalog && !variant && isNonEmpty3(catalog.appId) && catalog.catalogItemId === item.reference.id ? single : UNSUPPORTED;
2860
- },
2972
+ eligibility,
2861
2973
  openOrder: openOrder3,
2862
2974
  reopenOrder: reopenOrder3,
2863
- readAccess: readAccess3
2975
+ readAccess: readAccess3,
2976
+ itemPayment
2864
2977
  };
2978
+ function eligibility(item) {
2979
+ const single = singleUnitOf(KIND3, item);
2980
+ if (!single.eligible) return single;
2981
+ const catalog = item.catalogReference;
2982
+ const variant = catalog?.options && Object.keys(catalog.options).length > 0;
2983
+ return catalog && !variant && isNonEmpty3(catalog.appId) && catalog.catalogItemId === item.reference.id ? single : UNSUPPORTED;
2984
+ }
2985
+ function itemPayment(item) {
2986
+ const catalog = item.catalogReference;
2987
+ if (!eligibility(item).eligible || catalog?.appId.toLowerCase() !== WIX_STORES_APP) return null;
2988
+ return { catalogItem: { catalogItemId: catalog.catalogItemId, catalogAppId: WIX_STORES_APP }, verticalRefOf: (orderId) => ({ orderId }) };
2989
+ }
2865
2990
  function classifyCart(lines) {
2866
2991
  if (lines.length === 0 || lines.some((line) => line.route === "resolving" || line.route === "unavailable")) return "blocked";
2867
2992
  const apple = lines.filter((line) => line.route === "appleIap");
@@ -2908,6 +3033,7 @@ export {
2908
3033
  createIapCommerce,
2909
3034
  createWorkerOrderRefStore,
2910
3035
  iapPurchaseFields,
3036
+ itemPaymentEnabled,
2911
3037
  onlineProgramOrders,
2912
3038
  pricingPlanOrders,
2913
3039
  storesProductOrders
@@ -663,15 +663,18 @@ var IAP_CATALOG_KINDS = ["onlineProgram", "storesProduct", "pricingPlan"];
663
663
 
664
664
  // ../../core/sdk/iap/src/wix-payments-contract.ts
665
665
  var HIMALAYA_SERVE_IAP_ROUTE = { prefix: "/himalaya-serve/v1/iap" };
666
- var APPLE_SALE_RULES = {
667
- onlineProgram: { appProductId: (id) => id, productType: "NON_CONSUMABLE" }
668
- };
666
+ var STORES_ITEM_PAYMENT_ENABLED = false;
667
+ var STORES_PRODUCT_SALE_RULE = { appProductId: (id) => id, productType: "NON_CONSUMABLE" };
668
+ var ONLINE_PROGRAM_SALE_RULE = { appProductId: (id) => id, productType: "NON_CONSUMABLE" };
669
+ var APPLE_SALE_RULES = STORES_ITEM_PAYMENT_ENABLED ? { onlineProgram: ONLINE_PROGRAM_SALE_RULE, storesProduct: STORES_PRODUCT_SALE_RULE } : { onlineProgram: ONLINE_PROGRAM_SALE_RULE };
669
670
 
670
671
  // ../../core/sdk/iap/src/mapping-source.ts
671
672
  function iapMappingSource() {
672
673
  return createWixIapMappingSource({ binding: sharedHostAppBindingSource(), call: hostWixCall });
673
674
  }
674
675
  function createWixIapMappingSource(deps) {
676
+ const rules = deps.rules ?? APPLE_SALE_RULES;
677
+ const appProductIdOf = (reference) => reference.id ? rules[reference.kind]?.appProductId(reference.id) : void 0;
675
678
  return {
676
679
  // Only a binding the host actually returned: a read that failed is re-asked on the next load.
677
680
  active: async () => await deps.binding.current() !== null,
@@ -682,14 +685,11 @@ function createWixIapMappingSource(deps) {
682
685
  if (scope.siteId && !sameId(scope.siteId, binding.siteId)) return references.map((reference) => ({ reference, route: "unavailable" }));
683
686
  const asked = [...new Set(references.flatMap((reference) => appProductIdOf(reference) ?? []))];
684
687
  const mapped = await resolveAll(deps.call, binding, asked);
685
- return references.map((reference) => decide(reference, binding, mapped));
688
+ return references.map((reference) => decide(reference, binding, mapped.get(appProductIdOf(reference) ?? ""), rules[reference.kind]));
686
689
  }
687
690
  }
688
691
  };
689
692
  }
690
- function appProductIdOf(reference) {
691
- return reference.id ? APPLE_SALE_RULES[reference.kind]?.appProductId(reference.id) : void 0;
692
- }
693
693
  var PATH = `${HIMALAYA_SERVE_IAP_ROUTE.prefix}/mappings`;
694
694
  var BATCH = 100;
695
695
  async function resolveAll(call, binding, ids) {
@@ -713,11 +713,9 @@ function decodeMappings(reply) {
713
713
  return [m.appProductId, { storeProductId: m.storeProductId, type: String(m.type ?? ""), active: m.active === true }];
714
714
  });
715
715
  }
716
- function decide(reference, binding, mapped) {
717
- const id = appProductIdOf(reference);
718
- const mapping = id ? mapped.get(id) : void 0;
719
- if (!mapping) return { reference, route: "regular" };
720
- if (!mapping.active || mapping.type !== APPLE_SALE_RULES[reference.kind]?.productType) return { reference, route: "unavailable" };
716
+ function decide(reference, binding, mapping, rule) {
717
+ if (!mapping || !rule) return { reference, route: "regular" };
718
+ if (!mapping.active || mapping.type !== rule.productType) return { reference, route: "unavailable" };
721
719
  return { reference, route: "appleIap", productId: mapping.storeProductId, mappingRevision: `${binding.purchasesAppId}:${mapping.storeProductId}` };
722
720
  }
723
721
  function sameId(a, b) {
@@ -1022,6 +1020,15 @@ function wixApiGlobal() {
1022
1020
  function startPaymentCall(scope, wixTransactionId) {
1023
1021
  return post(scope, "/payments/start", { appId: scope.binding.purchasesAppId, wixTransactionId });
1024
1022
  }
1023
+ function startItemPaymentCall(scope, item) {
1024
+ return post(scope, "/payments/start-item", { appId: scope.binding.purchasesAppId, item: { catalogItemId: item.catalogItemId, catalogAppId: item.catalogAppId } });
1025
+ }
1026
+ function catalogItemOf(raw) {
1027
+ const item = isObject3(raw) ? raw : {};
1028
+ const { catalogItemId, catalogAppId } = item;
1029
+ const valid = typeof catalogItemId === "string" && catalogItemId.length > 0 && catalogItemId.length <= 36 && isUUID(catalogAppId);
1030
+ return valid ? { catalogItemId, catalogAppId } : null;
1031
+ }
1025
1032
  function completePaymentCall(scope, signedTransaction) {
1026
1033
  return post(scope, "/payments/complete", { appId: scope.binding.purchasesAppId, apple: { signedTransaction } });
1027
1034
  }
@@ -1036,6 +1043,12 @@ function decodeStarted(raw, expected) {
1036
1043
  const payment = decodePayment(raw.payment, expected);
1037
1044
  return payment && { payment, storeProductId: raw.storeProductId, appAccountToken: raw.appAccountToken };
1038
1045
  }
1046
+ function decodeStartedItem(raw, expected) {
1047
+ if (!isObject3(raw) || !isUUID(raw.ecomOrderId)) return null;
1048
+ const started = decodeStarted(raw, expected);
1049
+ if (!started || started.payment.appProductId !== expected.catalogItemId) return null;
1050
+ return { ...started, ecomOrderId: raw.ecomOrderId };
1051
+ }
1039
1052
  function decodePaymentAnswer(raw, expected) {
1040
1053
  return isObject3(raw) ? decodePayment(raw.payment, expected) : null;
1041
1054
  }
@@ -1158,6 +1171,19 @@ function createWixIapClient(deps) {
1158
1171
  }
1159
1172
  });
1160
1173
  }
1174
+ function startItemPayment(input) {
1175
+ const item = catalogItemOf(input.item);
1176
+ if (!item) return Promise.resolve(failure("startItemPayment", "invalidArgument"));
1177
+ return runUnrepeatable({
1178
+ operation: "startItemPayment",
1179
+ codes: START_ITEM_PAYMENT_CODES,
1180
+ request: (scope) => startItemPaymentCall(scope, item),
1181
+ decode: (raw, scope) => {
1182
+ const started = decodeStartedItem(raw, { ...expectationOf2(scope), catalogItemId: item.catalogItemId });
1183
+ return started && { status: "started", ...started };
1184
+ }
1185
+ });
1186
+ }
1161
1187
  function completePayment(transaction) {
1162
1188
  const refusal = refuseProof(transaction);
1163
1189
  if (refusal) return Promise.resolve(refusal);
@@ -1184,11 +1210,18 @@ function createWixIapClient(deps) {
1184
1210
  });
1185
1211
  }
1186
1212
  async function run(spec) {
1213
+ return (await execute(spec)).result;
1214
+ }
1215
+ async function runUnrepeatable(spec) {
1216
+ const { result, handedOff } = await execute(spec);
1217
+ return handedOff && isUndecided(result) ? outcomeUnknown(result) : result;
1218
+ }
1219
+ async function execute(spec) {
1187
1220
  const scope = await resolveScope(deps.session.current(), spec.operation);
1188
- if ("failure" in scope) return scope.failure;
1221
+ if ("failure" in scope) return { result: scope.failure, handedOff: false };
1189
1222
  const sent = await send(scope, spec);
1190
- if ("failure" in sent) return sent.failure;
1191
- return spec.decode(sent.answer, scope) ?? failure(spec.operation, "invalidResponse");
1223
+ if ("failure" in sent) return { result: sent.failure, handedOff: sent.handedOff };
1224
+ return { result: spec.decode(sent.answer, scope) ?? failure(spec.operation, "invalidResponse"), handedOff: true };
1192
1225
  }
1193
1226
  async function resolveScope(session, operation) {
1194
1227
  if (session.kind !== "member") return refused(operation, "authRequired");
@@ -1209,12 +1242,12 @@ function createWixIapClient(deps) {
1209
1242
  }
1210
1243
  async function send(scope, spec) {
1211
1244
  const transport = deps.transport ?? bridgeTransport();
1212
- if (!transport) return refused(spec.operation, "notEnabled");
1213
- if (!isCurrent(scope.session)) return refused(spec.operation, "sessionChanged");
1245
+ if (!transport) return notSent(spec.operation, "notEnabled");
1246
+ if (!isCurrent(scope.session)) return notSent(spec.operation, "sessionChanged");
1214
1247
  const expectation = boundExpectation(scope.session, deps.transport == null);
1215
- if (expectation === "refuse") return refused(spec.operation, "notEnabled");
1248
+ if (expectation === "refuse") return notSent(spec.operation, "notEnabled");
1216
1249
  const outcome = await attempt(transport, spec.request(scope), spec, expectation);
1217
- return isCurrent(scope.session) ? outcome : refused(spec.operation, "sessionChanged");
1250
+ return isCurrent(scope.session) ? outcome : { failure: failure(spec.operation, "sessionChanged"), handedOff: true };
1218
1251
  }
1219
1252
  function boundExpectation(session, liveHost) {
1220
1253
  const source = deps.session;
@@ -1225,16 +1258,27 @@ function createWixIapClient(deps) {
1225
1258
  function isCurrent(session) {
1226
1259
  return deps.session.current().generation === session.generation;
1227
1260
  }
1228
- return { startPayment, completePayment, getPayment };
1261
+ return { startPayment, startItemPayment, completePayment, getPayment };
1229
1262
  }
1230
1263
  async function attempt(transport, call, spec, expectation) {
1231
1264
  try {
1232
1265
  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);
1233
1266
  return { answer };
1234
1267
  } catch (error) {
1235
- return { failure: classifyFailure(error, spec.operation, spec.codes) };
1268
+ return { failure: classifyFailure(error, spec.operation, spec.codes), handedOff: true };
1236
1269
  }
1237
1270
  }
1271
+ function notSent(operation, kind) {
1272
+ return { failure: failure(operation, kind), handedOff: false };
1273
+ }
1274
+ function isUndecided(result) {
1275
+ const failed = result;
1276
+ return failed.status === "failed" && UNDECIDED.has(failed.kind);
1277
+ }
1278
+ function outcomeUnknown(failed) {
1279
+ const status = failed.httpStatus === void 0 ? {} : { httpStatus: failed.httpStatus };
1280
+ return { status: "outcomeUnknown", operation: "startItemPayment", kind: failed.kind, ...status };
1281
+ }
1238
1282
  async function read(call, operation) {
1239
1283
  try {
1240
1284
  return { value: await call() };
@@ -1270,6 +1314,14 @@ var START_PAYMENT_CODES = [
1270
1314
  "PRODUCT_NOT_AVAILABLE",
1271
1315
  "ALREADY_OWNED"
1272
1316
  ];
1317
+ var START_ITEM_PAYMENT_CODES = [
1318
+ "PRODUCT_NOT_AVAILABLE",
1319
+ "ALREADY_OWNED",
1320
+ "ITEM_NOT_AVAILABLE",
1321
+ "SITE_NOT_ACCEPTING_PAYMENTS",
1322
+ "UNSUPPORTED_ORDER"
1323
+ ];
1324
+ var UNDECIDED = /* @__PURE__ */ new Set(["unavailable", "sessionChanged", "invalidResponse"]);
1273
1325
  var COMPLETE_PAYMENT_CODES = [
1274
1326
  "INVALID_PURCHASE",
1275
1327
  "OWNED_BY_ANOTHER_CUSTOMER",
@@ -1417,6 +1469,8 @@ export {
1417
1469
  IAP_CATALOG_KINDS,
1418
1470
  MAX_AUTOMATIC_ATTEMPTS,
1419
1471
  MAX_RETRY_DELAY_MS,
1472
+ STORES_ITEM_PAYMENT_ENABLED,
1473
+ STORES_PRODUCT_SALE_RULE,
1420
1474
  appleManagedStore,
1421
1475
  consume,
1422
1476
  createHostSession,