@wix/himalaya-cli 0.1490.0 → 0.1492.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-contract.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +9 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +6 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +9 -3
- package/dist/cli.mjs +0 -1
- package/package.json +2 -2
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/community-club-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/events-meetups-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/owner-lite/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/restaurant-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/retail-store-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-hosted-sites.ts +60 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-overview/index.ts +21 -7
|
@@ -113,7 +113,7 @@ export interface WixIapPayment {
|
|
|
113
113
|
refundedDate?: string;
|
|
114
114
|
}
|
|
115
115
|
export type WixIapOperation = "startPayment" | "startItemPayment" | "completePayment" | "getPayment";
|
|
116
|
-
export type StartPaymentErrorCode = "NOT_PENDING" | "WRONG_PAYMENT_METHOD" | "NOT_ORDER_BUYER" | "UNSUPPORTED_ORDER" | "PRODUCT_NOT_AVAILABLE" | "ALREADY_OWNED";
|
|
116
|
+
export type StartPaymentErrorCode = "NOT_PENDING" | "WRONG_PAYMENT_METHOD" | "NOT_ORDER_BUYER" | "UNSUPPORTED_ORDER" | "PRODUCT_NOT_AVAILABLE" | "ALREADY_OWNED" | "APP_NOT_CONFIGURED" | "SUBSCRIPTION_NOT_IN_APP" | "ALREADY_SUBSCRIBED";
|
|
117
117
|
export type StartItemPaymentErrorCode = "PRODUCT_NOT_AVAILABLE" | "ALREADY_OWNED" | "ITEM_NOT_AVAILABLE" | "SITE_NOT_ACCEPTING_PAYMENTS" | "UNSUPPORTED_ORDER";
|
|
118
118
|
export type CompletePaymentErrorCode = "INVALID_PURCHASE" | "OWNED_BY_ANOTHER_CUSTOMER" | "PURCHASE_REVOKED" | "NOT_PURCHASED" | "ZERO_PRICE" | "NO_MATCHING_PAYMENT" | "PAYMENT_NOT_PENDING" | "APP_NOT_CONFIGURED";
|
|
119
119
|
export type GetPaymentErrorCode = "NOT_FOUND";
|
|
@@ -1019,7 +1019,7 @@ function wixApiGlobal() {
|
|
|
1019
1019
|
|
|
1020
1020
|
// ../../core/sdk/iap/src/wix-payments-wire.ts
|
|
1021
1021
|
function startPaymentCall(scope, wixTransactionId) {
|
|
1022
|
-
return post(scope, "/payments/start", {
|
|
1022
|
+
return post(scope, "/payments/start", { appleBundleId: scope.binding.bundleId, wixTransactionId });
|
|
1023
1023
|
}
|
|
1024
1024
|
function startItemPaymentCall(scope, item) {
|
|
1025
1025
|
return post(scope, "/payments/start-item", { appId: scope.binding.purchasesAppId, item: { catalogItemId: item.catalogItemId, catalogAppId: item.catalogAppId } });
|
|
@@ -1031,7 +1031,7 @@ function catalogItemOf(raw) {
|
|
|
1031
1031
|
return valid ? { catalogItemId, catalogAppId } : null;
|
|
1032
1032
|
}
|
|
1033
1033
|
function completePaymentCall(scope, signedTransaction) {
|
|
1034
|
-
return post(scope, "/payments/complete", {
|
|
1034
|
+
return post(scope, "/payments/complete", { appleBundleId: scope.binding.bundleId, apple: { signedTransaction } });
|
|
1035
1035
|
}
|
|
1036
1036
|
function paymentCall(scope, paymentId) {
|
|
1037
1037
|
return get2(scope, `/payments/${encodeURIComponent(paymentId)}`);
|
|
@@ -1313,7 +1313,10 @@ var START_PAYMENT_CODES = [
|
|
|
1313
1313
|
"NOT_ORDER_BUYER",
|
|
1314
1314
|
"UNSUPPORTED_ORDER",
|
|
1315
1315
|
"PRODUCT_NOT_AVAILABLE",
|
|
1316
|
-
"ALREADY_OWNED"
|
|
1316
|
+
"ALREADY_OWNED",
|
|
1317
|
+
"APP_NOT_CONFIGURED",
|
|
1318
|
+
"SUBSCRIPTION_NOT_IN_APP",
|
|
1319
|
+
"ALREADY_SUBSCRIBED"
|
|
1317
1320
|
];
|
|
1318
1321
|
var START_ITEM_PAYMENT_CODES = [
|
|
1319
1322
|
"PRODUCT_NOT_AVAILABLE",
|
|
@@ -1922,6 +1925,9 @@ function createWixOrderBackend(deps) {
|
|
|
1922
1925
|
}
|
|
1923
1926
|
async function startRefusal(sale, ref, failure3) {
|
|
1924
1927
|
if (failure3.kind !== "application") return failureStop(failure3);
|
|
1928
|
+
if (failure3.code === "SUBSCRIPTION_NOT_IN_APP" || failure3.code === "ALREADY_SUBSCRIBED") {
|
|
1929
|
+
return stopWith("rejected", "paymentRefused");
|
|
1930
|
+
}
|
|
1925
1931
|
if (failure3.code === "ALREADY_OWNED") return alreadyPaid(sale, ref);
|
|
1926
1932
|
if (failure3.code === "NOT_PENDING" || failure3.code === "NOT_ORDER_BUYER") forget(sale, sale.catalogRef);
|
|
1927
1933
|
return stopWith("rejected", failure3.code === "NOT_PENDING" ? "orderClosed" : "paymentRefused");
|
|
@@ -1028,7 +1028,7 @@ function wixApiGlobal() {
|
|
|
1028
1028
|
|
|
1029
1029
|
// ../../core/sdk/iap/src/wix-payments-wire.ts
|
|
1030
1030
|
function startPaymentCall(scope, wixTransactionId) {
|
|
1031
|
-
return post(scope, "/payments/start", {
|
|
1031
|
+
return post(scope, "/payments/start", { appleBundleId: scope.binding.bundleId, wixTransactionId });
|
|
1032
1032
|
}
|
|
1033
1033
|
function startItemPaymentCall(scope, item) {
|
|
1034
1034
|
return post(scope, "/payments/start-item", { appId: scope.binding.purchasesAppId, item: { catalogItemId: item.catalogItemId, catalogAppId: item.catalogAppId } });
|
|
@@ -1040,7 +1040,7 @@ function catalogItemOf(raw) {
|
|
|
1040
1040
|
return valid ? { catalogItemId, catalogAppId } : null;
|
|
1041
1041
|
}
|
|
1042
1042
|
function completePaymentCall(scope, signedTransaction) {
|
|
1043
|
-
return post(scope, "/payments/complete", {
|
|
1043
|
+
return post(scope, "/payments/complete", { appleBundleId: scope.binding.bundleId, apple: { signedTransaction } });
|
|
1044
1044
|
}
|
|
1045
1045
|
function paymentCall(scope, paymentId) {
|
|
1046
1046
|
return get(scope, `/payments/${encodeURIComponent(paymentId)}`);
|
|
@@ -1322,7 +1322,10 @@ var START_PAYMENT_CODES = [
|
|
|
1322
1322
|
"NOT_ORDER_BUYER",
|
|
1323
1323
|
"UNSUPPORTED_ORDER",
|
|
1324
1324
|
"PRODUCT_NOT_AVAILABLE",
|
|
1325
|
-
"ALREADY_OWNED"
|
|
1325
|
+
"ALREADY_OWNED",
|
|
1326
|
+
"APP_NOT_CONFIGURED",
|
|
1327
|
+
"SUBSCRIPTION_NOT_IN_APP",
|
|
1328
|
+
"ALREADY_SUBSCRIBED"
|
|
1326
1329
|
];
|
|
1327
1330
|
var START_ITEM_PAYMENT_CODES = [
|
|
1328
1331
|
"PRODUCT_NOT_AVAILABLE",
|
|
@@ -1585,7 +1585,7 @@ function wixApiGlobal() {
|
|
|
1585
1585
|
|
|
1586
1586
|
// ../../core/sdk/iap/src/wix-payments-wire.ts
|
|
1587
1587
|
function startPaymentCall(scope, wixTransactionId) {
|
|
1588
|
-
return post(scope, "/payments/start", {
|
|
1588
|
+
return post(scope, "/payments/start", { appleBundleId: scope.binding.bundleId, wixTransactionId });
|
|
1589
1589
|
}
|
|
1590
1590
|
function startItemPaymentCall(scope, item) {
|
|
1591
1591
|
return post(scope, "/payments/start-item", { appId: scope.binding.purchasesAppId, item: { catalogItemId: item.catalogItemId, catalogAppId: item.catalogAppId } });
|
|
@@ -1597,7 +1597,7 @@ function catalogItemOf(raw) {
|
|
|
1597
1597
|
return valid ? { catalogItemId, catalogAppId } : null;
|
|
1598
1598
|
}
|
|
1599
1599
|
function completePaymentCall(scope, signedTransaction) {
|
|
1600
|
-
return post(scope, "/payments/complete", {
|
|
1600
|
+
return post(scope, "/payments/complete", { appleBundleId: scope.binding.bundleId, apple: { signedTransaction } });
|
|
1601
1601
|
}
|
|
1602
1602
|
function paymentCall(scope, paymentId) {
|
|
1603
1603
|
return get2(scope, `/payments/${encodeURIComponent(paymentId)}`);
|
|
@@ -1879,7 +1879,10 @@ var START_PAYMENT_CODES = [
|
|
|
1879
1879
|
"NOT_ORDER_BUYER",
|
|
1880
1880
|
"UNSUPPORTED_ORDER",
|
|
1881
1881
|
"PRODUCT_NOT_AVAILABLE",
|
|
1882
|
-
"ALREADY_OWNED"
|
|
1882
|
+
"ALREADY_OWNED",
|
|
1883
|
+
"APP_NOT_CONFIGURED",
|
|
1884
|
+
"SUBSCRIPTION_NOT_IN_APP",
|
|
1885
|
+
"ALREADY_SUBSCRIBED"
|
|
1883
1886
|
];
|
|
1884
1887
|
var START_ITEM_PAYMENT_CODES = [
|
|
1885
1888
|
"PRODUCT_NOT_AVAILABLE",
|
|
@@ -2482,6 +2485,9 @@ function createWixOrderBackend(deps) {
|
|
|
2482
2485
|
}
|
|
2483
2486
|
async function startRefusal(sale, ref, failure3) {
|
|
2484
2487
|
if (failure3.kind !== "application") return failureStop(failure3);
|
|
2488
|
+
if (failure3.code === "SUBSCRIPTION_NOT_IN_APP" || failure3.code === "ALREADY_SUBSCRIBED") {
|
|
2489
|
+
return stopWith("rejected", "paymentRefused");
|
|
2490
|
+
}
|
|
2485
2491
|
if (failure3.code === "ALREADY_OWNED") return alreadyPaid(sale, ref);
|
|
2486
2492
|
if (failure3.code === "NOT_PENDING" || failure3.code === "NOT_ORDER_BUYER") forget(sale, sale.catalogRef);
|
|
2487
2493
|
return stopWith("rejected", failure3.code === "NOT_PENDING" ? "orderClosed" : "paymentRefused");
|
package/dist/cli.mjs
CHANGED
|
@@ -22149,7 +22149,6 @@ function resolveIdiom(tokens2, ctx = {}) {
|
|
|
22149
22149
|
var IDIOM_CONTEXTS, UNSAFE_KEYS;
|
|
22150
22150
|
var init_idiom = __esm({
|
|
22151
22151
|
"../../core/ts/src/idiom.ts"() {
|
|
22152
|
-
"use strict";
|
|
22153
22152
|
IDIOM_CONTEXTS = {
|
|
22154
22153
|
ios: { native: ["ios"] },
|
|
22155
22154
|
android: { native: ["material"] },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1492.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "7aba2d162be36ebf4054e60bba00ab84930e4a00bf727faafad1fe83"
|
|
75
75
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// The businesses an EMBEDDING HOST says the signed-in owner owns — or null when there is no
|
|
2
|
+
// such host.
|
|
3
|
+
//
|
|
4
|
+
// Standalone, an owner screen lists businesses itself (`querySites`, account level) and reads
|
|
5
|
+
// each one with `site.forSite(msid)`, which stamps `wix-site-id` on that call. Embedded, the
|
|
6
|
+
// host owns site selection: its data source signs every call for the business the user picked
|
|
7
|
+
// and drops a worker-sent `wix-site-id`, so a fan-out read ONE business N times. A host that
|
|
8
|
+
// opts in supplies its own list instead (`HimalayaOwnedSitesDataSource` on iOS / Android, the
|
|
9
|
+
// `ownedSites` prop on web) and answers `himi.wix.ownedSites` with it; the embed then routes a
|
|
10
|
+
// `site.forSite(msid)` call to the host's per-site call for any id on that list and refuses
|
|
11
|
+
// every other id. So a worker reads the list here and keeps using `site.forSite` unchanged.
|
|
12
|
+
//
|
|
13
|
+
// A rejection is "not hosted": a standalone shell has no handler for the verb, and an older embed
|
|
14
|
+
// predates it. Callers then do exactly what they did before. A host that opted in but cannot list
|
|
15
|
+
// answers `{ error }` instead, which THROWS here: falling back to `querySites` would read the
|
|
16
|
+
// account through the host's single-site signer and fan out to ids the host then refuses.
|
|
17
|
+
|
|
18
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
19
|
+
|
|
20
|
+
export const OWNED_SITES_ACTION = "himi.wix.ownedSites";
|
|
21
|
+
|
|
22
|
+
export interface HostedSite {
|
|
23
|
+
/** The business's metaSiteId — what `site.forSite` takes. */
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
logoUrl?: string;
|
|
27
|
+
color?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function text(v: unknown): string {
|
|
31
|
+
return typeof v === "string" ? v.trim() : "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The host's list, in the host's order; [] is a real answer (an owner with no businesses).
|
|
35
|
+
* null when the verb is unanswered or the answer is not a list. Throws the host's `{ error }`. */
|
|
36
|
+
export async function hostOwnedSites(): Promise<HostedSite[] | null> {
|
|
37
|
+
let value: unknown;
|
|
38
|
+
try {
|
|
39
|
+
value = await dispatch(OWNED_SITES_ACTION);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
// Native hosts resolve the payload itself; some web shells wrap it as `{ payload }`.
|
|
44
|
+
const body = value as { sites?: unknown; error?: unknown; payload?: { sites?: unknown; error?: unknown } } | null;
|
|
45
|
+
const error = body?.error ?? body?.payload?.error;
|
|
46
|
+
if (typeof error === "string") throw new Error(error || "The host could not list your businesses");
|
|
47
|
+
const raw = body?.sites ?? body?.payload?.sites;
|
|
48
|
+
if (!Array.isArray(raw)) return null;
|
|
49
|
+
const sites: HostedSite[] = [];
|
|
50
|
+
for (const entry of raw) {
|
|
51
|
+
const e = (entry ?? {}) as Record<string, unknown>;
|
|
52
|
+
const id = text(e.id);
|
|
53
|
+
if (!id) continue;
|
|
54
|
+
const site: HostedSite = { id, name: text(e.name) };
|
|
55
|
+
if (text(e.logoUrl)) site.logoUrl = text(e.logoUrl);
|
|
56
|
+
if (text(e.color)) site.color = text(e.color);
|
|
57
|
+
sites.push(site);
|
|
58
|
+
}
|
|
59
|
+
return sites;
|
|
60
|
+
}
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
// or one whose mint fails, resolves to `null` and renders as "—" beside the others rather
|
|
23
23
|
// than throwing the whole screen into its error state. A rollup that disappears because one
|
|
24
24
|
// of five businesses is unreachable is worse than one that says so in a row.
|
|
25
|
+
//
|
|
26
|
+
// EMBEDDED, THE HOST NAMES THE BUSINESSES. A host that owns site selection (Symphony's Manage
|
|
27
|
+
// Wix) signs each call itself and would drop the per-call `wix-site-id`, so it supplies the
|
|
28
|
+
// owner's sites instead (`hostOwnedSites`) and resolves each `site.forSite(msid)` call against
|
|
29
|
+
// that list. The list replaces rung 1 only; the fan-out below is identical either way.
|
|
25
30
|
|
|
26
31
|
import { defineService } from "@himalaya/state";
|
|
27
32
|
import { querySites, type WixSite } from "@himalaya/wix-site-list";
|
|
@@ -31,6 +36,7 @@ import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_share
|
|
|
31
36
|
import { DEMO_SITES, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
|
|
32
37
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
33
38
|
import { pickSite, pickedSite } from "../_shared/owner-site-pick.js";
|
|
39
|
+
import { hostOwnedSites } from "../_shared/owner-hosted-sites.js";
|
|
34
40
|
|
|
35
41
|
/** Mirrors the Home dashboard's "needs attention" definition, so a number here means the
|
|
36
42
|
* same thing it means after the owner drills into that business. */
|
|
@@ -176,16 +182,24 @@ async function attentionCount(msid: string): Promise<number | null> {
|
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
|
|
185
|
+
/** Rung 1: the host's list when embedded, else the account's own (`querySites`). */
|
|
186
|
+
async function listBusinesses(): Promise<Array<{ id: string; name: string }>> {
|
|
187
|
+
const unnamed = () => copyParam("ownerOverview.unnamedBusiness", "Business");
|
|
188
|
+
const hosted = await hostOwnedSites();
|
|
189
|
+
if (hosted) return hosted.map((h) => ({ id: h.id, name: h.name || unnamed() }));
|
|
190
|
+
const res = await querySites({ query: { cursorPaging: { limit: 50 } } });
|
|
191
|
+
return (res.sites ?? [])
|
|
192
|
+
.filter((r: WixSite) => r?.id)
|
|
193
|
+
.map((r: WixSite) => ({
|
|
194
|
+
id: r.id || "",
|
|
195
|
+
name: r.displayName || (r as { name?: string }).name || unnamed(),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
179
199
|
async function loadRollup(): Promise<OverviewState> {
|
|
180
200
|
if (isOwnerPreviewDemo()) return demoRollup();
|
|
181
201
|
try {
|
|
182
|
-
const
|
|
183
|
-
const businesses = (res.sites ?? [])
|
|
184
|
-
.filter((r: WixSite) => r?.id)
|
|
185
|
-
.map((r: WixSite) => ({
|
|
186
|
-
id: r.id || "",
|
|
187
|
-
name: r.displayName || (r as { name?: string }).name || copyParam("ownerOverview.unnamedBusiness", "Business"),
|
|
188
|
-
}));
|
|
202
|
+
const businesses = await listBusinesses();
|
|
189
203
|
if (businesses.length === 0) return shape({ status: "ready", rows: [] });
|
|
190
204
|
|
|
191
205
|
// THE FAN-OUT. Concurrent, one business each, active scope untouched.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// The businesses an EMBEDDING HOST says the signed-in owner owns — or null when there is no
|
|
2
|
+
// such host.
|
|
3
|
+
//
|
|
4
|
+
// Standalone, an owner screen lists businesses itself (`querySites`, account level) and reads
|
|
5
|
+
// each one with `site.forSite(msid)`, which stamps `wix-site-id` on that call. Embedded, the
|
|
6
|
+
// host owns site selection: its data source signs every call for the business the user picked
|
|
7
|
+
// and drops a worker-sent `wix-site-id`, so a fan-out read ONE business N times. A host that
|
|
8
|
+
// opts in supplies its own list instead (`HimalayaOwnedSitesDataSource` on iOS / Android, the
|
|
9
|
+
// `ownedSites` prop on web) and answers `himi.wix.ownedSites` with it; the embed then routes a
|
|
10
|
+
// `site.forSite(msid)` call to the host's per-site call for any id on that list and refuses
|
|
11
|
+
// every other id. So a worker reads the list here and keeps using `site.forSite` unchanged.
|
|
12
|
+
//
|
|
13
|
+
// A rejection is "not hosted": a standalone shell has no handler for the verb, and an older embed
|
|
14
|
+
// predates it. Callers then do exactly what they did before. A host that opted in but cannot list
|
|
15
|
+
// answers `{ error }` instead, which THROWS here: falling back to `querySites` would read the
|
|
16
|
+
// account through the host's single-site signer and fan out to ids the host then refuses.
|
|
17
|
+
|
|
18
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
19
|
+
|
|
20
|
+
export const OWNED_SITES_ACTION = "himi.wix.ownedSites";
|
|
21
|
+
|
|
22
|
+
export interface HostedSite {
|
|
23
|
+
/** The business's metaSiteId — what `site.forSite` takes. */
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
logoUrl?: string;
|
|
27
|
+
color?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function text(v: unknown): string {
|
|
31
|
+
return typeof v === "string" ? v.trim() : "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The host's list, in the host's order; [] is a real answer (an owner with no businesses).
|
|
35
|
+
* null when the verb is unanswered or the answer is not a list. Throws the host's `{ error }`. */
|
|
36
|
+
export async function hostOwnedSites(): Promise<HostedSite[] | null> {
|
|
37
|
+
let value: unknown;
|
|
38
|
+
try {
|
|
39
|
+
value = await dispatch(OWNED_SITES_ACTION);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
// Native hosts resolve the payload itself; some web shells wrap it as `{ payload }`.
|
|
44
|
+
const body = value as { sites?: unknown; error?: unknown; payload?: { sites?: unknown; error?: unknown } } | null;
|
|
45
|
+
const error = body?.error ?? body?.payload?.error;
|
|
46
|
+
if (typeof error === "string") throw new Error(error || "The host could not list your businesses");
|
|
47
|
+
const raw = body?.sites ?? body?.payload?.sites;
|
|
48
|
+
if (!Array.isArray(raw)) return null;
|
|
49
|
+
const sites: HostedSite[] = [];
|
|
50
|
+
for (const entry of raw) {
|
|
51
|
+
const e = (entry ?? {}) as Record<string, unknown>;
|
|
52
|
+
const id = text(e.id);
|
|
53
|
+
if (!id) continue;
|
|
54
|
+
const site: HostedSite = { id, name: text(e.name) };
|
|
55
|
+
if (text(e.logoUrl)) site.logoUrl = text(e.logoUrl);
|
|
56
|
+
if (text(e.color)) site.color = text(e.color);
|
|
57
|
+
sites.push(site);
|
|
58
|
+
}
|
|
59
|
+
return sites;
|
|
60
|
+
}
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
// or one whose mint fails, resolves to `null` and renders as "—" beside the others rather
|
|
23
23
|
// than throwing the whole screen into its error state. A rollup that disappears because one
|
|
24
24
|
// of five businesses is unreachable is worse than one that says so in a row.
|
|
25
|
+
//
|
|
26
|
+
// EMBEDDED, THE HOST NAMES THE BUSINESSES. A host that owns site selection (Symphony's Manage
|
|
27
|
+
// Wix) signs each call itself and would drop the per-call `wix-site-id`, so it supplies the
|
|
28
|
+
// owner's sites instead (`hostOwnedSites`) and resolves each `site.forSite(msid)` call against
|
|
29
|
+
// that list. The list replaces rung 1 only; the fan-out below is identical either way.
|
|
25
30
|
|
|
26
31
|
import { defineService } from "@himalaya/state";
|
|
27
32
|
import { querySites, type WixSite } from "@himalaya/wix-site-list";
|
|
@@ -31,6 +36,7 @@ import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_share
|
|
|
31
36
|
import { DEMO_SITES, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
|
|
32
37
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
33
38
|
import { pickSite, pickedSite } from "../_shared/owner-site-pick.js";
|
|
39
|
+
import { hostOwnedSites } from "../_shared/owner-hosted-sites.js";
|
|
34
40
|
|
|
35
41
|
/** Mirrors the Home dashboard's "needs attention" definition, so a number here means the
|
|
36
42
|
* same thing it means after the owner drills into that business. */
|
|
@@ -176,16 +182,24 @@ async function attentionCount(msid: string): Promise<number | null> {
|
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
|
|
185
|
+
/** Rung 1: the host's list when embedded, else the account's own (`querySites`). */
|
|
186
|
+
async function listBusinesses(): Promise<Array<{ id: string; name: string }>> {
|
|
187
|
+
const unnamed = () => copyParam("ownerOverview.unnamedBusiness", "Business");
|
|
188
|
+
const hosted = await hostOwnedSites();
|
|
189
|
+
if (hosted) return hosted.map((h) => ({ id: h.id, name: h.name || unnamed() }));
|
|
190
|
+
const res = await querySites({ query: { cursorPaging: { limit: 50 } } });
|
|
191
|
+
return (res.sites ?? [])
|
|
192
|
+
.filter((r: WixSite) => r?.id)
|
|
193
|
+
.map((r: WixSite) => ({
|
|
194
|
+
id: r.id || "",
|
|
195
|
+
name: r.displayName || (r as { name?: string }).name || unnamed(),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
179
199
|
async function loadRollup(): Promise<OverviewState> {
|
|
180
200
|
if (isOwnerPreviewDemo()) return demoRollup();
|
|
181
201
|
try {
|
|
182
|
-
const
|
|
183
|
-
const businesses = (res.sites ?? [])
|
|
184
|
-
.filter((r: WixSite) => r?.id)
|
|
185
|
-
.map((r: WixSite) => ({
|
|
186
|
-
id: r.id || "",
|
|
187
|
-
name: r.displayName || (r as { name?: string }).name || copyParam("ownerOverview.unnamedBusiness", "Business"),
|
|
188
|
-
}));
|
|
202
|
+
const businesses = await listBusinesses();
|
|
189
203
|
if (businesses.length === 0) return shape({ status: "ready", rows: [] });
|
|
190
204
|
|
|
191
205
|
// THE FAN-OUT. Concurrent, one business each, active scope untouched.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// The businesses an EMBEDDING HOST says the signed-in owner owns — or null when there is no
|
|
2
|
+
// such host.
|
|
3
|
+
//
|
|
4
|
+
// Standalone, an owner screen lists businesses itself (`querySites`, account level) and reads
|
|
5
|
+
// each one with `site.forSite(msid)`, which stamps `wix-site-id` on that call. Embedded, the
|
|
6
|
+
// host owns site selection: its data source signs every call for the business the user picked
|
|
7
|
+
// and drops a worker-sent `wix-site-id`, so a fan-out read ONE business N times. A host that
|
|
8
|
+
// opts in supplies its own list instead (`HimalayaOwnedSitesDataSource` on iOS / Android, the
|
|
9
|
+
// `ownedSites` prop on web) and answers `himi.wix.ownedSites` with it; the embed then routes a
|
|
10
|
+
// `site.forSite(msid)` call to the host's per-site call for any id on that list and refuses
|
|
11
|
+
// every other id. So a worker reads the list here and keeps using `site.forSite` unchanged.
|
|
12
|
+
//
|
|
13
|
+
// A rejection is "not hosted": a standalone shell has no handler for the verb, and an older embed
|
|
14
|
+
// predates it. Callers then do exactly what they did before. A host that opted in but cannot list
|
|
15
|
+
// answers `{ error }` instead, which THROWS here: falling back to `querySites` would read the
|
|
16
|
+
// account through the host's single-site signer and fan out to ids the host then refuses.
|
|
17
|
+
|
|
18
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
19
|
+
|
|
20
|
+
export const OWNED_SITES_ACTION = "himi.wix.ownedSites";
|
|
21
|
+
|
|
22
|
+
export interface HostedSite {
|
|
23
|
+
/** The business's metaSiteId — what `site.forSite` takes. */
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
logoUrl?: string;
|
|
27
|
+
color?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function text(v: unknown): string {
|
|
31
|
+
return typeof v === "string" ? v.trim() : "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The host's list, in the host's order; [] is a real answer (an owner with no businesses).
|
|
35
|
+
* null when the verb is unanswered or the answer is not a list. Throws the host's `{ error }`. */
|
|
36
|
+
export async function hostOwnedSites(): Promise<HostedSite[] | null> {
|
|
37
|
+
let value: unknown;
|
|
38
|
+
try {
|
|
39
|
+
value = await dispatch(OWNED_SITES_ACTION);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
// Native hosts resolve the payload itself; some web shells wrap it as `{ payload }`.
|
|
44
|
+
const body = value as { sites?: unknown; error?: unknown; payload?: { sites?: unknown; error?: unknown } } | null;
|
|
45
|
+
const error = body?.error ?? body?.payload?.error;
|
|
46
|
+
if (typeof error === "string") throw new Error(error || "The host could not list your businesses");
|
|
47
|
+
const raw = body?.sites ?? body?.payload?.sites;
|
|
48
|
+
if (!Array.isArray(raw)) return null;
|
|
49
|
+
const sites: HostedSite[] = [];
|
|
50
|
+
for (const entry of raw) {
|
|
51
|
+
const e = (entry ?? {}) as Record<string, unknown>;
|
|
52
|
+
const id = text(e.id);
|
|
53
|
+
if (!id) continue;
|
|
54
|
+
const site: HostedSite = { id, name: text(e.name) };
|
|
55
|
+
if (text(e.logoUrl)) site.logoUrl = text(e.logoUrl);
|
|
56
|
+
if (text(e.color)) site.color = text(e.color);
|
|
57
|
+
sites.push(site);
|
|
58
|
+
}
|
|
59
|
+
return sites;
|
|
60
|
+
}
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
// or one whose mint fails, resolves to `null` and renders as "—" beside the others rather
|
|
23
23
|
// than throwing the whole screen into its error state. A rollup that disappears because one
|
|
24
24
|
// of five businesses is unreachable is worse than one that says so in a row.
|
|
25
|
+
//
|
|
26
|
+
// EMBEDDED, THE HOST NAMES THE BUSINESSES. A host that owns site selection (Symphony's Manage
|
|
27
|
+
// Wix) signs each call itself and would drop the per-call `wix-site-id`, so it supplies the
|
|
28
|
+
// owner's sites instead (`hostOwnedSites`) and resolves each `site.forSite(msid)` call against
|
|
29
|
+
// that list. The list replaces rung 1 only; the fan-out below is identical either way.
|
|
25
30
|
|
|
26
31
|
import { defineService } from "@himalaya/state";
|
|
27
32
|
import { querySites, type WixSite } from "@himalaya/wix-site-list";
|
|
@@ -31,6 +36,7 @@ import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_share
|
|
|
31
36
|
import { DEMO_SITES, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
|
|
32
37
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
33
38
|
import { pickSite, pickedSite } from "../_shared/owner-site-pick.js";
|
|
39
|
+
import { hostOwnedSites } from "../_shared/owner-hosted-sites.js";
|
|
34
40
|
|
|
35
41
|
/** Mirrors the Home dashboard's "needs attention" definition, so a number here means the
|
|
36
42
|
* same thing it means after the owner drills into that business. */
|
|
@@ -176,16 +182,24 @@ async function attentionCount(msid: string): Promise<number | null> {
|
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
|
|
185
|
+
/** Rung 1: the host's list when embedded, else the account's own (`querySites`). */
|
|
186
|
+
async function listBusinesses(): Promise<Array<{ id: string; name: string }>> {
|
|
187
|
+
const unnamed = () => copyParam("ownerOverview.unnamedBusiness", "Business");
|
|
188
|
+
const hosted = await hostOwnedSites();
|
|
189
|
+
if (hosted) return hosted.map((h) => ({ id: h.id, name: h.name || unnamed() }));
|
|
190
|
+
const res = await querySites({ query: { cursorPaging: { limit: 50 } } });
|
|
191
|
+
return (res.sites ?? [])
|
|
192
|
+
.filter((r: WixSite) => r?.id)
|
|
193
|
+
.map((r: WixSite) => ({
|
|
194
|
+
id: r.id || "",
|
|
195
|
+
name: r.displayName || (r as { name?: string }).name || unnamed(),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
179
199
|
async function loadRollup(): Promise<OverviewState> {
|
|
180
200
|
if (isOwnerPreviewDemo()) return demoRollup();
|
|
181
201
|
try {
|
|
182
|
-
const
|
|
183
|
-
const businesses = (res.sites ?? [])
|
|
184
|
-
.filter((r: WixSite) => r?.id)
|
|
185
|
-
.map((r: WixSite) => ({
|
|
186
|
-
id: r.id || "",
|
|
187
|
-
name: r.displayName || (r as { name?: string }).name || copyParam("ownerOverview.unnamedBusiness", "Business"),
|
|
188
|
-
}));
|
|
202
|
+
const businesses = await listBusinesses();
|
|
189
203
|
if (businesses.length === 0) return shape({ status: "ready", rows: [] });
|
|
190
204
|
|
|
191
205
|
// THE FAN-OUT. Concurrent, one business each, active scope untouched.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// The businesses an EMBEDDING HOST says the signed-in owner owns — or null when there is no
|
|
2
|
+
// such host.
|
|
3
|
+
//
|
|
4
|
+
// Standalone, an owner screen lists businesses itself (`querySites`, account level) and reads
|
|
5
|
+
// each one with `site.forSite(msid)`, which stamps `wix-site-id` on that call. Embedded, the
|
|
6
|
+
// host owns site selection: its data source signs every call for the business the user picked
|
|
7
|
+
// and drops a worker-sent `wix-site-id`, so a fan-out read ONE business N times. A host that
|
|
8
|
+
// opts in supplies its own list instead (`HimalayaOwnedSitesDataSource` on iOS / Android, the
|
|
9
|
+
// `ownedSites` prop on web) and answers `himi.wix.ownedSites` with it; the embed then routes a
|
|
10
|
+
// `site.forSite(msid)` call to the host's per-site call for any id on that list and refuses
|
|
11
|
+
// every other id. So a worker reads the list here and keeps using `site.forSite` unchanged.
|
|
12
|
+
//
|
|
13
|
+
// A rejection is "not hosted": a standalone shell has no handler for the verb, and an older embed
|
|
14
|
+
// predates it. Callers then do exactly what they did before. A host that opted in but cannot list
|
|
15
|
+
// answers `{ error }` instead, which THROWS here: falling back to `querySites` would read the
|
|
16
|
+
// account through the host's single-site signer and fan out to ids the host then refuses.
|
|
17
|
+
|
|
18
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
19
|
+
|
|
20
|
+
export const OWNED_SITES_ACTION = "himi.wix.ownedSites";
|
|
21
|
+
|
|
22
|
+
export interface HostedSite {
|
|
23
|
+
/** The business's metaSiteId — what `site.forSite` takes. */
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
logoUrl?: string;
|
|
27
|
+
color?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function text(v: unknown): string {
|
|
31
|
+
return typeof v === "string" ? v.trim() : "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The host's list, in the host's order; [] is a real answer (an owner with no businesses).
|
|
35
|
+
* null when the verb is unanswered or the answer is not a list. Throws the host's `{ error }`. */
|
|
36
|
+
export async function hostOwnedSites(): Promise<HostedSite[] | null> {
|
|
37
|
+
let value: unknown;
|
|
38
|
+
try {
|
|
39
|
+
value = await dispatch(OWNED_SITES_ACTION);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
// Native hosts resolve the payload itself; some web shells wrap it as `{ payload }`.
|
|
44
|
+
const body = value as { sites?: unknown; error?: unknown; payload?: { sites?: unknown; error?: unknown } } | null;
|
|
45
|
+
const error = body?.error ?? body?.payload?.error;
|
|
46
|
+
if (typeof error === "string") throw new Error(error || "The host could not list your businesses");
|
|
47
|
+
const raw = body?.sites ?? body?.payload?.sites;
|
|
48
|
+
if (!Array.isArray(raw)) return null;
|
|
49
|
+
const sites: HostedSite[] = [];
|
|
50
|
+
for (const entry of raw) {
|
|
51
|
+
const e = (entry ?? {}) as Record<string, unknown>;
|
|
52
|
+
const id = text(e.id);
|
|
53
|
+
if (!id) continue;
|
|
54
|
+
const site: HostedSite = { id, name: text(e.name) };
|
|
55
|
+
if (text(e.logoUrl)) site.logoUrl = text(e.logoUrl);
|
|
56
|
+
if (text(e.color)) site.color = text(e.color);
|
|
57
|
+
sites.push(site);
|
|
58
|
+
}
|
|
59
|
+
return sites;
|
|
60
|
+
}
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
// or one whose mint fails, resolves to `null` and renders as "—" beside the others rather
|
|
23
23
|
// than throwing the whole screen into its error state. A rollup that disappears because one
|
|
24
24
|
// of five businesses is unreachable is worse than one that says so in a row.
|
|
25
|
+
//
|
|
26
|
+
// EMBEDDED, THE HOST NAMES THE BUSINESSES. A host that owns site selection (Symphony's Manage
|
|
27
|
+
// Wix) signs each call itself and would drop the per-call `wix-site-id`, so it supplies the
|
|
28
|
+
// owner's sites instead (`hostOwnedSites`) and resolves each `site.forSite(msid)` call against
|
|
29
|
+
// that list. The list replaces rung 1 only; the fan-out below is identical either way.
|
|
25
30
|
|
|
26
31
|
import { defineService } from "@himalaya/state";
|
|
27
32
|
import { querySites, type WixSite } from "@himalaya/wix-site-list";
|
|
@@ -31,6 +36,7 @@ import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_share
|
|
|
31
36
|
import { DEMO_SITES, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
|
|
32
37
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
33
38
|
import { pickSite, pickedSite } from "../_shared/owner-site-pick.js";
|
|
39
|
+
import { hostOwnedSites } from "../_shared/owner-hosted-sites.js";
|
|
34
40
|
|
|
35
41
|
/** Mirrors the Home dashboard's "needs attention" definition, so a number here means the
|
|
36
42
|
* same thing it means after the owner drills into that business. */
|
|
@@ -176,16 +182,24 @@ async function attentionCount(msid: string): Promise<number | null> {
|
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
|
|
185
|
+
/** Rung 1: the host's list when embedded, else the account's own (`querySites`). */
|
|
186
|
+
async function listBusinesses(): Promise<Array<{ id: string; name: string }>> {
|
|
187
|
+
const unnamed = () => copyParam("ownerOverview.unnamedBusiness", "Business");
|
|
188
|
+
const hosted = await hostOwnedSites();
|
|
189
|
+
if (hosted) return hosted.map((h) => ({ id: h.id, name: h.name || unnamed() }));
|
|
190
|
+
const res = await querySites({ query: { cursorPaging: { limit: 50 } } });
|
|
191
|
+
return (res.sites ?? [])
|
|
192
|
+
.filter((r: WixSite) => r?.id)
|
|
193
|
+
.map((r: WixSite) => ({
|
|
194
|
+
id: r.id || "",
|
|
195
|
+
name: r.displayName || (r as { name?: string }).name || unnamed(),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
179
199
|
async function loadRollup(): Promise<OverviewState> {
|
|
180
200
|
if (isOwnerPreviewDemo()) return demoRollup();
|
|
181
201
|
try {
|
|
182
|
-
const
|
|
183
|
-
const businesses = (res.sites ?? [])
|
|
184
|
-
.filter((r: WixSite) => r?.id)
|
|
185
|
-
.map((r: WixSite) => ({
|
|
186
|
-
id: r.id || "",
|
|
187
|
-
name: r.displayName || (r as { name?: string }).name || copyParam("ownerOverview.unnamedBusiness", "Business"),
|
|
188
|
-
}));
|
|
202
|
+
const businesses = await listBusinesses();
|
|
189
203
|
if (businesses.length === 0) return shape({ status: "ready", rows: [] });
|
|
190
204
|
|
|
191
205
|
// THE FAN-OUT. Concurrent, one business each, active scope untouched.
|