@wix/himalaya-cli 0.903.0 → 0.905.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/stdlib/wix-sdk/events/src/index.d.ts +39 -21
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-events.mjs +1 -9
- package/dist/cli.mjs +74 -20
- package/guides/sdk-reference.json +5 -5
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +6 -3
- package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/branded-lite/dev/index.ts +8 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/community-club/dev/index.ts +4 -2
- package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/events-meetups/dev/index.ts +4 -2
- package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/gym-fitness/dev/index.ts +8 -4
- package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/nonprofit-cause/dev/index.ts +4 -2
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/podcast-creator/dev/index.ts +4 -2
- package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/portfolio-creative/dev/index.ts +6 -3
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/restaurant/dev/index.ts +4 -2
- package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/retail-store/dev/index.ts +4 -2
- package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +45 -3
- package/templates/yoga-studio/dev/index.ts +6 -3
- package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +45 -3
|
@@ -14313,7 +14313,7 @@
|
|
|
14313
14313
|
"name": "WixEvent",
|
|
14314
14314
|
"kind": "interface",
|
|
14315
14315
|
"jsdoc": "",
|
|
14316
|
-
"decl": "export interface WixEvent {\n id: string;\n title?: string;\n /** Normally one of `WixEventStatus`,
|
|
14316
|
+
"decl": "export interface WixEvent {\n id: string;\n title?: string;\n /** Normally one of `WixEventStatus` — `UPCOMING` (published and scheduled to start),\n * `STARTED`, `ENDED`, `CANCELED`, `DRAFT`. Events v1 called the first of those `SCHEDULED`,\n * and this SDK reads v3, so a row here never carries `SCHEDULED`.\n *\n * Deliberately NOT narrowed to that union: `decodeEvent` fills this from the server's\n * `status` and passes a value it does not recognise straight through, because dropping or\n * rewriting one would lose a real event. A union here would be a claim this SDK cannot\n * enforce. Compare against `WixEventStatus` when you need the set it knows. */\n eventStatus?: string;\n /** EventType: RSVP | TICKETS | EXTERNAL | NO_REGISTRATION */\n eventType?: string;\n scheduling?: WixEventScheduling;\n location?: WixEventLocation;\n mainImage?: WixEventImage;\n slug?: string;\n about?: string;\n description?: string;\n}"
|
|
14317
14317
|
},
|
|
14318
14318
|
{
|
|
14319
14319
|
"name": "WixGetEventListResponse",
|
|
@@ -14336,20 +14336,20 @@
|
|
|
14336
14336
|
{
|
|
14337
14337
|
"name": "EVENT_STATUSES",
|
|
14338
14338
|
"kind": "const",
|
|
14339
|
-
"jsdoc": "/** The
|
|
14340
|
-
"decl": "export const EVENT_STATUSES = Object.freeze([\"
|
|
14339
|
+
"jsdoc": "/** The event statuses this SDK knows the server stores — the Events **v3** set, because that\n * is the API `queryEvents` and `getEvent` call. `UPCOMING` is a published event that has not\n * started; v1 called that one `SCHEDULED`, and v3 does not use that spelling at all, so a\n * filter copied from v1 docs matches nothing. The one source for `WixEventStatus` below, so\n * the two cannot drift.\n *\n * Known, not exhaustive. The server owns this list and versions it — it has already been\n * renamed once, and v3 declares an `UNKNOWN_EVENT_STATUS` of its own — so nothing here\n * refuses a value that is absent from it. Use it to recognise a status, never to reject one.\n *\n * Exported because `WixEventStatus` is declared in terms of it: the generated SDK reference\n * ships each exported declaration verbatim, and a reader copying a type that names a symbol\n * they cannot see gets TS2304.\n *\n * Frozen because `as const` is erased: it makes the TYPE readonly and leaves an ordinary\n * mutable array behind. Unexported that was academic; exported it is not — module bindings\n * share one array object, so a `push` from any untyped caller would edit the set every\n * caller in that realm reads. The freeze makes the runtime keep the promise the type makes. */",
|
|
14340
|
+
"decl": "export const EVENT_STATUSES = Object.freeze([\"UPCOMING\", \"STARTED\", \"ENDED\", \"CANCELED\", \"DRAFT\"] as const);"
|
|
14341
14341
|
},
|
|
14342
14342
|
{
|
|
14343
14343
|
"name": "WixEventStatus",
|
|
14344
14344
|
"kind": "type",
|
|
14345
|
-
"jsdoc": "/** One of the
|
|
14345
|
+
"jsdoc": "/** One of the event statuses this SDK knows about. `WixQueryEventsOptions.statuses` accepts\n * these and suggests them as you type, but does not require them — see that field. */",
|
|
14346
14346
|
"decl": "export type WixEventStatus = (typeof EVENT_STATUSES)[number];"
|
|
14347
14347
|
},
|
|
14348
14348
|
{
|
|
14349
14349
|
"name": "WixQueryEventsOptions",
|
|
14350
14350
|
"kind": "interface",
|
|
14351
14351
|
"jsdoc": "",
|
|
14352
|
-
"decl": "export interface WixQueryEventsOptions {\n /** Server-side WQL filter/sort for Events v3. Unlike the legacy convenience\n * options below, these criteria are applied before paging. */\n query?: { filter?: Record<string, unknown>; sort?: Array<{ fieldName: string; order: \"ASC\" | \"DESC\" }>; paging?: { limit?: number; offset?: number } };\n /** Page size. */\n limit?: number;\n /** Page offset. */\n offset?: number;\n /** Status filter (e.g. `[\"
|
|
14352
|
+
"decl": "export interface WixQueryEventsOptions {\n /** Server-side WQL filter/sort for Events v3. Unlike the legacy convenience\n * options below, these criteria are applied before paging. */\n query?: { filter?: Record<string, unknown>; sort?: Array<{ fieldName: string; order: \"ASC\" | \"DESC\" }>; paging?: { limit?: number; offset?: number } };\n /** Page size. */\n limit?: number;\n /** Page offset. */\n offset?: number;\n /** Status filter (e.g. `[\"UPCOMING\"]`), matched exactly against each row's `eventStatus`.\n * Omitted → all statuses returned; a value no row carries selects nothing.\n *\n * This route is Events **v3**, whose statuses are `UPCOMING` (published and scheduled to\n * start), `STARTED`, `ENDED`, `CANCELED` and `DRAFT`. Events v1 named the first of those\n * `SCHEDULED`, so a filter copied from v1 docs matches no row a v3 site returns — reach\n * for `UPCOMING` instead.\n *\n * The type suggests `EVENT_STATUSES` without closing on them: the server owns that list and\n * versions it, so a value it adds later must reach the match rather than be refused on the\n * strength of a copy that has fallen behind. A status this SDK does not know is filtered on\n * like any other and selects the rows that carry it — or none, which is the honest answer\n * and one a caller can read.\n *\n * Applied to the fetched page, after paging. To filter server-side instead, use\n * `query.filter`, which is passed through unchanged. */\n statuses?: Array<WixEventStatus | (string & {})>;\n /** Sort property (the Owner list orders by \"start\"). */\n order?: string;\n /** Free-t\n/* … */"
|
|
14353
14353
|
},
|
|
14354
14354
|
{
|
|
14355
14355
|
"name": "decodeEvent",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.905.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": [
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"artifactId": "himalaya-cli"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
"falconPackageHash": "
|
|
67
|
+
"falconPackageHash": "4712eb68e7f2ecbd289330a1edda23126be3218b4a5869c6fecbde14"
|
|
68
68
|
}
|
|
@@ -24644,7 +24644,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
24644
24644
|
"contentType": "application/javascript+ts-bundle",
|
|
24645
24645
|
"declaredCapabilities": [
|
|
24646
24646
|
"wix_api",
|
|
24647
|
-
"share"
|
|
24647
|
+
"share",
|
|
24648
|
+
"local_database"
|
|
24648
24649
|
],
|
|
24649
24650
|
"minBinaryVersion": "0.1.0",
|
|
24650
24651
|
"bundleVersion": "0.0.1"
|
|
@@ -25178,7 +25179,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
25178
25179
|
"contentType": "application/javascript+ts-bundle",
|
|
25179
25180
|
"declaredCapabilities": [
|
|
25180
25181
|
"wix_api",
|
|
25181
|
-
"share"
|
|
25182
|
+
"share",
|
|
25183
|
+
"local_database"
|
|
25182
25184
|
],
|
|
25183
25185
|
"minBinaryVersion": "0.1.0",
|
|
25184
25186
|
"bundleVersion": "0.0.1"
|
|
@@ -27104,7 +27106,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
27104
27106
|
"contentType": "application/javascript+ts-bundle",
|
|
27105
27107
|
"declaredCapabilities": [
|
|
27106
27108
|
"wix_api",
|
|
27107
|
-
"share"
|
|
27109
|
+
"share",
|
|
27110
|
+
"local_database"
|
|
27108
27111
|
],
|
|
27109
27112
|
"minBinaryVersion": "0.1.0",
|
|
27110
27113
|
"bundleVersion": "0.0.1"
|
|
@@ -20,6 +20,39 @@ import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-save
|
|
|
20
20
|
import { readSavedIds } from "../_shared/himi-blog-saved.js";
|
|
21
21
|
import { wixMediaUrl } from "@himalaya/wix-media";
|
|
22
22
|
|
|
23
|
+
/** Latched once the member feed is refused because of WHERE the app is running rather
|
|
24
|
+
* than because of the request — see the catch in `loadExtras`. Module scope, so it
|
|
25
|
+
* survives every refresh of this worker and is reset only by a fresh boot. */
|
|
26
|
+
let feedSurfaceRefused = false;
|
|
27
|
+
|
|
28
|
+
/** True for the one refusal that can never change while the app keeps running: the web
|
|
29
|
+
* bridge reporting that this host is not reachable from a browser at all. Deliberately
|
|
30
|
+
* narrower than `isBridgeUnavailable` — a 502/503 is an outage worth retrying, and only
|
|
31
|
+
* this typed refusal is permanent. */
|
|
32
|
+
function isFeedSurfaceRefusal(error: unknown): boolean {
|
|
33
|
+
return /webwix_owner_only/.test(String((error as Error)?.message ?? error));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** In-flight feed reads, keyed by the container they are for.
|
|
37
|
+
*
|
|
38
|
+
* The latch alone still let ONE duplicate through: two Home refreshes that overlap both read
|
|
39
|
+
* `feedSurfaceRefused === false` before the first rejection reaches the catch. Sharing the
|
|
40
|
+
* request closes that window — the second refresh awaits the first instead of sending its own,
|
|
41
|
+
* and both see the same rejection, so the latch is set exactly once.
|
|
42
|
+
*
|
|
43
|
+
* Keyed by container, not a single slot: `active` is the most recently active group, recomputed
|
|
44
|
+
* per refresh from a live `queryGroups`, so two overlapping refreshes can legitimately want
|
|
45
|
+
* DIFFERENT containers. A single shared promise would hand the second one the first one's feed. */
|
|
46
|
+
const feedInFlight = new Map<string, Promise<Awaited<ReturnType<typeof listFeedItems>>>>();
|
|
47
|
+
|
|
48
|
+
function feedFor(containerId: string, limit: number): Promise<Awaited<ReturnType<typeof listFeedItems>>> {
|
|
49
|
+
const pending = feedInFlight.get(containerId);
|
|
50
|
+
if (pending) return pending;
|
|
51
|
+
const started = listFeedItems(containerId, limit).finally(() => { feedInFlight.delete(containerId); });
|
|
52
|
+
feedInFlight.set(containerId, started);
|
|
53
|
+
return started;
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
interface ProductFeature {
|
|
24
57
|
id: string;
|
|
25
58
|
name: string;
|
|
@@ -714,10 +747,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
714
747
|
const response = await queryGroups({ paging: { limit: 12 } });
|
|
715
748
|
const groups = (response.groups ?? []).filter((group) => group.id);
|
|
716
749
|
if (verticals.includes("groups")) extras.groupCards = groups.slice(0, 6).map(groupCard);
|
|
717
|
-
if (verticals.includes("feed") && groups.length) {
|
|
750
|
+
if (verticals.includes("feed") && groups.length && !feedSurfaceRefused) {
|
|
718
751
|
const active = groups.slice().sort((a, b) =>
|
|
719
752
|
new Date(b.lastActivityDate ?? 0).getTime() - new Date(a.lastActivityDate ?? 0).getTime())[0];
|
|
720
|
-
const feed = await
|
|
753
|
+
const feed = await feedFor(active.id, 8);
|
|
721
754
|
const profiles = feed.profiles ?? [];
|
|
722
755
|
const items = (feed.feedItems ?? []).filter((item) => item.feedItemId);
|
|
723
756
|
extras.feedHighlights = items.slice(0, 5).map((item) => {
|
|
@@ -742,7 +775,15 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
742
775
|
}))
|
|
743
776
|
.slice(0, 12);
|
|
744
777
|
}
|
|
745
|
-
} catch {
|
|
778
|
+
} catch (error) {
|
|
779
|
+
// This particular refusal is PERMANENT, not a blip: in a browser the member feed's
|
|
780
|
+
// host cannot be reached at all, so asking again can only fail again. Retrying on
|
|
781
|
+
// every Home visit spent one doomed round trip each time and filled the error log
|
|
782
|
+
// with something nobody can act on. Latch it once and stop asking; on a phone,
|
|
783
|
+
// where the call does work, this never trips.
|
|
784
|
+
if (isFeedSurfaceRefusal(error)) feedSurfaceRefused = true;
|
|
785
|
+
/* otherwise collapse silently, as before */
|
|
786
|
+
}
|
|
746
787
|
})());
|
|
747
788
|
}
|
|
748
789
|
await Promise.all(jobs);
|
|
@@ -893,6 +934,7 @@ function baseState(): State {
|
|
|
893
934
|
* let a stale failure clobber a newer success (returning `undefined` keeps the
|
|
894
935
|
* current service state; see JSRuntimeBootstrap.applyNext). */
|
|
895
936
|
let refreshGen = 0;
|
|
937
|
+
|
|
896
938
|
/** Last successful featured list — catch paths read this when the action's
|
|
897
939
|
* `state` snapshot was captured before a racing refresh painted products. */
|
|
898
940
|
let lastFeaturedProducts: ProductFeature[] = [];
|
|
@@ -74683,7 +74683,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
74683
74683
|
"contentType": "application/javascript+ts-bundle",
|
|
74684
74684
|
"declaredCapabilities": [
|
|
74685
74685
|
"wix_api",
|
|
74686
|
-
"share"
|
|
74686
|
+
"share",
|
|
74687
|
+
"local_database"
|
|
74687
74688
|
],
|
|
74688
74689
|
"minBinaryVersion": "0.1.0",
|
|
74689
74690
|
"bundleVersion": "0.0.1"
|
|
@@ -75217,7 +75218,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
75217
75218
|
"contentType": "application/javascript+ts-bundle",
|
|
75218
75219
|
"declaredCapabilities": [
|
|
75219
75220
|
"wix_api",
|
|
75220
|
-
"share"
|
|
75221
|
+
"share",
|
|
75222
|
+
"local_database"
|
|
75221
75223
|
],
|
|
75222
75224
|
"minBinaryVersion": "0.1.0",
|
|
75223
75225
|
"bundleVersion": "0.0.1"
|
|
@@ -78305,7 +78307,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
78305
78307
|
"open_url",
|
|
78306
78308
|
"calendar",
|
|
78307
78309
|
"share",
|
|
78308
|
-
"wix_cashier"
|
|
78310
|
+
"wix_cashier",
|
|
78311
|
+
"local_database"
|
|
78309
78312
|
],
|
|
78310
78313
|
"minBinaryVersion": "0.1.0",
|
|
78311
78314
|
"bundleVersion": "0.0.1"
|
|
@@ -79847,7 +79850,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
79847
79850
|
"contentType": "application/javascript+ts-bundle",
|
|
79848
79851
|
"declaredCapabilities": [
|
|
79849
79852
|
"wix_api",
|
|
79850
|
-
"share"
|
|
79853
|
+
"share",
|
|
79854
|
+
"local_database"
|
|
79851
79855
|
],
|
|
79852
79856
|
"minBinaryVersion": "0.1.0",
|
|
79853
79857
|
"bundleVersion": "0.0.1"
|
|
@@ -20,6 +20,39 @@ import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-save
|
|
|
20
20
|
import { readSavedIds } from "../_shared/himi-blog-saved.js";
|
|
21
21
|
import { wixMediaUrl } from "@himalaya/wix-media";
|
|
22
22
|
|
|
23
|
+
/** Latched once the member feed is refused because of WHERE the app is running rather
|
|
24
|
+
* than because of the request — see the catch in `loadExtras`. Module scope, so it
|
|
25
|
+
* survives every refresh of this worker and is reset only by a fresh boot. */
|
|
26
|
+
let feedSurfaceRefused = false;
|
|
27
|
+
|
|
28
|
+
/** True for the one refusal that can never change while the app keeps running: the web
|
|
29
|
+
* bridge reporting that this host is not reachable from a browser at all. Deliberately
|
|
30
|
+
* narrower than `isBridgeUnavailable` — a 502/503 is an outage worth retrying, and only
|
|
31
|
+
* this typed refusal is permanent. */
|
|
32
|
+
function isFeedSurfaceRefusal(error: unknown): boolean {
|
|
33
|
+
return /webwix_owner_only/.test(String((error as Error)?.message ?? error));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** In-flight feed reads, keyed by the container they are for.
|
|
37
|
+
*
|
|
38
|
+
* The latch alone still let ONE duplicate through: two Home refreshes that overlap both read
|
|
39
|
+
* `feedSurfaceRefused === false` before the first rejection reaches the catch. Sharing the
|
|
40
|
+
* request closes that window — the second refresh awaits the first instead of sending its own,
|
|
41
|
+
* and both see the same rejection, so the latch is set exactly once.
|
|
42
|
+
*
|
|
43
|
+
* Keyed by container, not a single slot: `active` is the most recently active group, recomputed
|
|
44
|
+
* per refresh from a live `queryGroups`, so two overlapping refreshes can legitimately want
|
|
45
|
+
* DIFFERENT containers. A single shared promise would hand the second one the first one's feed. */
|
|
46
|
+
const feedInFlight = new Map<string, Promise<Awaited<ReturnType<typeof listFeedItems>>>>();
|
|
47
|
+
|
|
48
|
+
function feedFor(containerId: string, limit: number): Promise<Awaited<ReturnType<typeof listFeedItems>>> {
|
|
49
|
+
const pending = feedInFlight.get(containerId);
|
|
50
|
+
if (pending) return pending;
|
|
51
|
+
const started = listFeedItems(containerId, limit).finally(() => { feedInFlight.delete(containerId); });
|
|
52
|
+
feedInFlight.set(containerId, started);
|
|
53
|
+
return started;
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
interface ProductFeature {
|
|
24
57
|
id: string;
|
|
25
58
|
name: string;
|
|
@@ -714,10 +747,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
714
747
|
const response = await queryGroups({ paging: { limit: 12 } });
|
|
715
748
|
const groups = (response.groups ?? []).filter((group) => group.id);
|
|
716
749
|
if (verticals.includes("groups")) extras.groupCards = groups.slice(0, 6).map(groupCard);
|
|
717
|
-
if (verticals.includes("feed") && groups.length) {
|
|
750
|
+
if (verticals.includes("feed") && groups.length && !feedSurfaceRefused) {
|
|
718
751
|
const active = groups.slice().sort((a, b) =>
|
|
719
752
|
new Date(b.lastActivityDate ?? 0).getTime() - new Date(a.lastActivityDate ?? 0).getTime())[0];
|
|
720
|
-
const feed = await
|
|
753
|
+
const feed = await feedFor(active.id, 8);
|
|
721
754
|
const profiles = feed.profiles ?? [];
|
|
722
755
|
const items = (feed.feedItems ?? []).filter((item) => item.feedItemId);
|
|
723
756
|
extras.feedHighlights = items.slice(0, 5).map((item) => {
|
|
@@ -742,7 +775,15 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
742
775
|
}))
|
|
743
776
|
.slice(0, 12);
|
|
744
777
|
}
|
|
745
|
-
} catch {
|
|
778
|
+
} catch (error) {
|
|
779
|
+
// This particular refusal is PERMANENT, not a blip: in a browser the member feed's
|
|
780
|
+
// host cannot be reached at all, so asking again can only fail again. Retrying on
|
|
781
|
+
// every Home visit spent one doomed round trip each time and filled the error log
|
|
782
|
+
// with something nobody can act on. Latch it once and stop asking; on a phone,
|
|
783
|
+
// where the call does work, this never trips.
|
|
784
|
+
if (isFeedSurfaceRefusal(error)) feedSurfaceRefused = true;
|
|
785
|
+
/* otherwise collapse silently, as before */
|
|
786
|
+
}
|
|
746
787
|
})());
|
|
747
788
|
}
|
|
748
789
|
await Promise.all(jobs);
|
|
@@ -893,6 +934,7 @@ function baseState(): State {
|
|
|
893
934
|
* let a stale failure clobber a newer success (returning `undefined` keeps the
|
|
894
935
|
* current service state; see JSRuntimeBootstrap.applyNext). */
|
|
895
936
|
let refreshGen = 0;
|
|
937
|
+
|
|
896
938
|
/** Last successful featured list — catch paths read this when the action's
|
|
897
939
|
* `state` snapshot was captured before a racing refresh painted products. */
|
|
898
940
|
let lastFeaturedProducts: ProductFeature[] = [];
|
|
@@ -17009,7 +17009,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
17009
17009
|
"open_url",
|
|
17010
17010
|
"calendar",
|
|
17011
17011
|
"share",
|
|
17012
|
-
"wix_cashier"
|
|
17012
|
+
"wix_cashier",
|
|
17013
|
+
"local_database"
|
|
17013
17014
|
],
|
|
17014
17015
|
"minBinaryVersion": "0.1.0",
|
|
17015
17016
|
"bundleVersion": "0.0.1"
|
|
@@ -18551,7 +18552,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
18551
18552
|
"contentType": "application/javascript+ts-bundle",
|
|
18552
18553
|
"declaredCapabilities": [
|
|
18553
18554
|
"wix_api",
|
|
18554
|
-
"share"
|
|
18555
|
+
"share",
|
|
18556
|
+
"local_database"
|
|
18555
18557
|
],
|
|
18556
18558
|
"minBinaryVersion": "0.1.0",
|
|
18557
18559
|
"bundleVersion": "0.0.1"
|
|
@@ -20,6 +20,39 @@ import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-save
|
|
|
20
20
|
import { readSavedIds } from "../_shared/himi-blog-saved.js";
|
|
21
21
|
import { wixMediaUrl } from "@himalaya/wix-media";
|
|
22
22
|
|
|
23
|
+
/** Latched once the member feed is refused because of WHERE the app is running rather
|
|
24
|
+
* than because of the request — see the catch in `loadExtras`. Module scope, so it
|
|
25
|
+
* survives every refresh of this worker and is reset only by a fresh boot. */
|
|
26
|
+
let feedSurfaceRefused = false;
|
|
27
|
+
|
|
28
|
+
/** True for the one refusal that can never change while the app keeps running: the web
|
|
29
|
+
* bridge reporting that this host is not reachable from a browser at all. Deliberately
|
|
30
|
+
* narrower than `isBridgeUnavailable` — a 502/503 is an outage worth retrying, and only
|
|
31
|
+
* this typed refusal is permanent. */
|
|
32
|
+
function isFeedSurfaceRefusal(error: unknown): boolean {
|
|
33
|
+
return /webwix_owner_only/.test(String((error as Error)?.message ?? error));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** In-flight feed reads, keyed by the container they are for.
|
|
37
|
+
*
|
|
38
|
+
* The latch alone still let ONE duplicate through: two Home refreshes that overlap both read
|
|
39
|
+
* `feedSurfaceRefused === false` before the first rejection reaches the catch. Sharing the
|
|
40
|
+
* request closes that window — the second refresh awaits the first instead of sending its own,
|
|
41
|
+
* and both see the same rejection, so the latch is set exactly once.
|
|
42
|
+
*
|
|
43
|
+
* Keyed by container, not a single slot: `active` is the most recently active group, recomputed
|
|
44
|
+
* per refresh from a live `queryGroups`, so two overlapping refreshes can legitimately want
|
|
45
|
+
* DIFFERENT containers. A single shared promise would hand the second one the first one's feed. */
|
|
46
|
+
const feedInFlight = new Map<string, Promise<Awaited<ReturnType<typeof listFeedItems>>>>();
|
|
47
|
+
|
|
48
|
+
function feedFor(containerId: string, limit: number): Promise<Awaited<ReturnType<typeof listFeedItems>>> {
|
|
49
|
+
const pending = feedInFlight.get(containerId);
|
|
50
|
+
if (pending) return pending;
|
|
51
|
+
const started = listFeedItems(containerId, limit).finally(() => { feedInFlight.delete(containerId); });
|
|
52
|
+
feedInFlight.set(containerId, started);
|
|
53
|
+
return started;
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
interface ProductFeature {
|
|
24
57
|
id: string;
|
|
25
58
|
name: string;
|
|
@@ -714,10 +747,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
714
747
|
const response = await queryGroups({ paging: { limit: 12 } });
|
|
715
748
|
const groups = (response.groups ?? []).filter((group) => group.id);
|
|
716
749
|
if (verticals.includes("groups")) extras.groupCards = groups.slice(0, 6).map(groupCard);
|
|
717
|
-
if (verticals.includes("feed") && groups.length) {
|
|
750
|
+
if (verticals.includes("feed") && groups.length && !feedSurfaceRefused) {
|
|
718
751
|
const active = groups.slice().sort((a, b) =>
|
|
719
752
|
new Date(b.lastActivityDate ?? 0).getTime() - new Date(a.lastActivityDate ?? 0).getTime())[0];
|
|
720
|
-
const feed = await
|
|
753
|
+
const feed = await feedFor(active.id, 8);
|
|
721
754
|
const profiles = feed.profiles ?? [];
|
|
722
755
|
const items = (feed.feedItems ?? []).filter((item) => item.feedItemId);
|
|
723
756
|
extras.feedHighlights = items.slice(0, 5).map((item) => {
|
|
@@ -742,7 +775,15 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
742
775
|
}))
|
|
743
776
|
.slice(0, 12);
|
|
744
777
|
}
|
|
745
|
-
} catch {
|
|
778
|
+
} catch (error) {
|
|
779
|
+
// This particular refusal is PERMANENT, not a blip: in a browser the member feed's
|
|
780
|
+
// host cannot be reached at all, so asking again can only fail again. Retrying on
|
|
781
|
+
// every Home visit spent one doomed round trip each time and filled the error log
|
|
782
|
+
// with something nobody can act on. Latch it once and stop asking; on a phone,
|
|
783
|
+
// where the call does work, this never trips.
|
|
784
|
+
if (isFeedSurfaceRefusal(error)) feedSurfaceRefused = true;
|
|
785
|
+
/* otherwise collapse silently, as before */
|
|
786
|
+
}
|
|
746
787
|
})());
|
|
747
788
|
}
|
|
748
789
|
await Promise.all(jobs);
|
|
@@ -893,6 +934,7 @@ function baseState(): State {
|
|
|
893
934
|
* let a stale failure clobber a newer success (returning `undefined` keeps the
|
|
894
935
|
* current service state; see JSRuntimeBootstrap.applyNext). */
|
|
895
936
|
let refreshGen = 0;
|
|
937
|
+
|
|
896
938
|
/** Last successful featured list — catch paths read this when the action's
|
|
897
939
|
* `state` snapshot was captured before a racing refresh painted products. */
|
|
898
940
|
let lastFeaturedProducts: ProductFeature[] = [];
|
|
@@ -15114,7 +15114,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
15114
15114
|
"open_url",
|
|
15115
15115
|
"calendar",
|
|
15116
15116
|
"share",
|
|
15117
|
-
"wix_cashier"
|
|
15117
|
+
"wix_cashier",
|
|
15118
|
+
"local_database"
|
|
15118
15119
|
],
|
|
15119
15120
|
"minBinaryVersion": "0.1.0",
|
|
15120
15121
|
"bundleVersion": "0.0.1"
|
|
@@ -16656,7 +16657,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
16656
16657
|
"contentType": "application/javascript+ts-bundle",
|
|
16657
16658
|
"declaredCapabilities": [
|
|
16658
16659
|
"wix_api",
|
|
16659
|
-
"share"
|
|
16660
|
+
"share",
|
|
16661
|
+
"local_database"
|
|
16660
16662
|
],
|
|
16661
16663
|
"minBinaryVersion": "0.1.0",
|
|
16662
16664
|
"bundleVersion": "0.0.1"
|
|
@@ -20,6 +20,39 @@ import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-save
|
|
|
20
20
|
import { readSavedIds } from "../_shared/himi-blog-saved.js";
|
|
21
21
|
import { wixMediaUrl } from "@himalaya/wix-media";
|
|
22
22
|
|
|
23
|
+
/** Latched once the member feed is refused because of WHERE the app is running rather
|
|
24
|
+
* than because of the request — see the catch in `loadExtras`. Module scope, so it
|
|
25
|
+
* survives every refresh of this worker and is reset only by a fresh boot. */
|
|
26
|
+
let feedSurfaceRefused = false;
|
|
27
|
+
|
|
28
|
+
/** True for the one refusal that can never change while the app keeps running: the web
|
|
29
|
+
* bridge reporting that this host is not reachable from a browser at all. Deliberately
|
|
30
|
+
* narrower than `isBridgeUnavailable` — a 502/503 is an outage worth retrying, and only
|
|
31
|
+
* this typed refusal is permanent. */
|
|
32
|
+
function isFeedSurfaceRefusal(error: unknown): boolean {
|
|
33
|
+
return /webwix_owner_only/.test(String((error as Error)?.message ?? error));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** In-flight feed reads, keyed by the container they are for.
|
|
37
|
+
*
|
|
38
|
+
* The latch alone still let ONE duplicate through: two Home refreshes that overlap both read
|
|
39
|
+
* `feedSurfaceRefused === false` before the first rejection reaches the catch. Sharing the
|
|
40
|
+
* request closes that window — the second refresh awaits the first instead of sending its own,
|
|
41
|
+
* and both see the same rejection, so the latch is set exactly once.
|
|
42
|
+
*
|
|
43
|
+
* Keyed by container, not a single slot: `active` is the most recently active group, recomputed
|
|
44
|
+
* per refresh from a live `queryGroups`, so two overlapping refreshes can legitimately want
|
|
45
|
+
* DIFFERENT containers. A single shared promise would hand the second one the first one's feed. */
|
|
46
|
+
const feedInFlight = new Map<string, Promise<Awaited<ReturnType<typeof listFeedItems>>>>();
|
|
47
|
+
|
|
48
|
+
function feedFor(containerId: string, limit: number): Promise<Awaited<ReturnType<typeof listFeedItems>>> {
|
|
49
|
+
const pending = feedInFlight.get(containerId);
|
|
50
|
+
if (pending) return pending;
|
|
51
|
+
const started = listFeedItems(containerId, limit).finally(() => { feedInFlight.delete(containerId); });
|
|
52
|
+
feedInFlight.set(containerId, started);
|
|
53
|
+
return started;
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
interface ProductFeature {
|
|
24
57
|
id: string;
|
|
25
58
|
name: string;
|
|
@@ -714,10 +747,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
714
747
|
const response = await queryGroups({ paging: { limit: 12 } });
|
|
715
748
|
const groups = (response.groups ?? []).filter((group) => group.id);
|
|
716
749
|
if (verticals.includes("groups")) extras.groupCards = groups.slice(0, 6).map(groupCard);
|
|
717
|
-
if (verticals.includes("feed") && groups.length) {
|
|
750
|
+
if (verticals.includes("feed") && groups.length && !feedSurfaceRefused) {
|
|
718
751
|
const active = groups.slice().sort((a, b) =>
|
|
719
752
|
new Date(b.lastActivityDate ?? 0).getTime() - new Date(a.lastActivityDate ?? 0).getTime())[0];
|
|
720
|
-
const feed = await
|
|
753
|
+
const feed = await feedFor(active.id, 8);
|
|
721
754
|
const profiles = feed.profiles ?? [];
|
|
722
755
|
const items = (feed.feedItems ?? []).filter((item) => item.feedItemId);
|
|
723
756
|
extras.feedHighlights = items.slice(0, 5).map((item) => {
|
|
@@ -742,7 +775,15 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
742
775
|
}))
|
|
743
776
|
.slice(0, 12);
|
|
744
777
|
}
|
|
745
|
-
} catch {
|
|
778
|
+
} catch (error) {
|
|
779
|
+
// This particular refusal is PERMANENT, not a blip: in a browser the member feed's
|
|
780
|
+
// host cannot be reached at all, so asking again can only fail again. Retrying on
|
|
781
|
+
// every Home visit spent one doomed round trip each time and filled the error log
|
|
782
|
+
// with something nobody can act on. Latch it once and stop asking; on a phone,
|
|
783
|
+
// where the call does work, this never trips.
|
|
784
|
+
if (isFeedSurfaceRefusal(error)) feedSurfaceRefused = true;
|
|
785
|
+
/* otherwise collapse silently, as before */
|
|
786
|
+
}
|
|
746
787
|
})());
|
|
747
788
|
}
|
|
748
789
|
await Promise.all(jobs);
|
|
@@ -893,6 +934,7 @@ function baseState(): State {
|
|
|
893
934
|
* let a stale failure clobber a newer success (returning `undefined` keeps the
|
|
894
935
|
* current service state; see JSRuntimeBootstrap.applyNext). */
|
|
895
936
|
let refreshGen = 0;
|
|
937
|
+
|
|
896
938
|
/** Last successful featured list — catch paths read this when the action's
|
|
897
939
|
* `state` snapshot was captured before a racing refresh painted products. */
|
|
898
940
|
let lastFeaturedProducts: ProductFeature[] = [];
|
|
@@ -27974,7 +27974,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
27974
27974
|
"contentType": "application/javascript+ts-bundle",
|
|
27975
27975
|
"declaredCapabilities": [
|
|
27976
27976
|
"wix_api",
|
|
27977
|
-
"share"
|
|
27977
|
+
"share",
|
|
27978
|
+
"local_database"
|
|
27978
27979
|
],
|
|
27979
27980
|
"minBinaryVersion": "0.1.0",
|
|
27980
27981
|
"bundleVersion": "0.0.1"
|
|
@@ -28508,7 +28509,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
28508
28509
|
"contentType": "application/javascript+ts-bundle",
|
|
28509
28510
|
"declaredCapabilities": [
|
|
28510
28511
|
"wix_api",
|
|
28511
|
-
"share"
|
|
28512
|
+
"share",
|
|
28513
|
+
"local_database"
|
|
28512
28514
|
],
|
|
28513
28515
|
"minBinaryVersion": "0.1.0",
|
|
28514
28516
|
"bundleVersion": "0.0.1"
|
|
@@ -30474,7 +30476,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
30474
30476
|
"open_url",
|
|
30475
30477
|
"calendar",
|
|
30476
30478
|
"share",
|
|
30477
|
-
"wix_cashier"
|
|
30479
|
+
"wix_cashier",
|
|
30480
|
+
"local_database"
|
|
30478
30481
|
],
|
|
30479
30482
|
"minBinaryVersion": "0.1.0",
|
|
30480
30483
|
"bundleVersion": "0.0.1"
|
|
@@ -32016,7 +32019,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
32016
32019
|
"contentType": "application/javascript+ts-bundle",
|
|
32017
32020
|
"declaredCapabilities": [
|
|
32018
32021
|
"wix_api",
|
|
32019
|
-
"share"
|
|
32022
|
+
"share",
|
|
32023
|
+
"local_database"
|
|
32020
32024
|
],
|
|
32021
32025
|
"minBinaryVersion": "0.1.0",
|
|
32022
32026
|
"bundleVersion": "0.0.1"
|
|
@@ -20,6 +20,39 @@ import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-save
|
|
|
20
20
|
import { readSavedIds } from "../_shared/himi-blog-saved.js";
|
|
21
21
|
import { wixMediaUrl } from "@himalaya/wix-media";
|
|
22
22
|
|
|
23
|
+
/** Latched once the member feed is refused because of WHERE the app is running rather
|
|
24
|
+
* than because of the request — see the catch in `loadExtras`. Module scope, so it
|
|
25
|
+
* survives every refresh of this worker and is reset only by a fresh boot. */
|
|
26
|
+
let feedSurfaceRefused = false;
|
|
27
|
+
|
|
28
|
+
/** True for the one refusal that can never change while the app keeps running: the web
|
|
29
|
+
* bridge reporting that this host is not reachable from a browser at all. Deliberately
|
|
30
|
+
* narrower than `isBridgeUnavailable` — a 502/503 is an outage worth retrying, and only
|
|
31
|
+
* this typed refusal is permanent. */
|
|
32
|
+
function isFeedSurfaceRefusal(error: unknown): boolean {
|
|
33
|
+
return /webwix_owner_only/.test(String((error as Error)?.message ?? error));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** In-flight feed reads, keyed by the container they are for.
|
|
37
|
+
*
|
|
38
|
+
* The latch alone still let ONE duplicate through: two Home refreshes that overlap both read
|
|
39
|
+
* `feedSurfaceRefused === false` before the first rejection reaches the catch. Sharing the
|
|
40
|
+
* request closes that window — the second refresh awaits the first instead of sending its own,
|
|
41
|
+
* and both see the same rejection, so the latch is set exactly once.
|
|
42
|
+
*
|
|
43
|
+
* Keyed by container, not a single slot: `active` is the most recently active group, recomputed
|
|
44
|
+
* per refresh from a live `queryGroups`, so two overlapping refreshes can legitimately want
|
|
45
|
+
* DIFFERENT containers. A single shared promise would hand the second one the first one's feed. */
|
|
46
|
+
const feedInFlight = new Map<string, Promise<Awaited<ReturnType<typeof listFeedItems>>>>();
|
|
47
|
+
|
|
48
|
+
function feedFor(containerId: string, limit: number): Promise<Awaited<ReturnType<typeof listFeedItems>>> {
|
|
49
|
+
const pending = feedInFlight.get(containerId);
|
|
50
|
+
if (pending) return pending;
|
|
51
|
+
const started = listFeedItems(containerId, limit).finally(() => { feedInFlight.delete(containerId); });
|
|
52
|
+
feedInFlight.set(containerId, started);
|
|
53
|
+
return started;
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
interface ProductFeature {
|
|
24
57
|
id: string;
|
|
25
58
|
name: string;
|
|
@@ -714,10 +747,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
714
747
|
const response = await queryGroups({ paging: { limit: 12 } });
|
|
715
748
|
const groups = (response.groups ?? []).filter((group) => group.id);
|
|
716
749
|
if (verticals.includes("groups")) extras.groupCards = groups.slice(0, 6).map(groupCard);
|
|
717
|
-
if (verticals.includes("feed") && groups.length) {
|
|
750
|
+
if (verticals.includes("feed") && groups.length && !feedSurfaceRefused) {
|
|
718
751
|
const active = groups.slice().sort((a, b) =>
|
|
719
752
|
new Date(b.lastActivityDate ?? 0).getTime() - new Date(a.lastActivityDate ?? 0).getTime())[0];
|
|
720
|
-
const feed = await
|
|
753
|
+
const feed = await feedFor(active.id, 8);
|
|
721
754
|
const profiles = feed.profiles ?? [];
|
|
722
755
|
const items = (feed.feedItems ?? []).filter((item) => item.feedItemId);
|
|
723
756
|
extras.feedHighlights = items.slice(0, 5).map((item) => {
|
|
@@ -742,7 +775,15 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
742
775
|
}))
|
|
743
776
|
.slice(0, 12);
|
|
744
777
|
}
|
|
745
|
-
} catch {
|
|
778
|
+
} catch (error) {
|
|
779
|
+
// This particular refusal is PERMANENT, not a blip: in a browser the member feed's
|
|
780
|
+
// host cannot be reached at all, so asking again can only fail again. Retrying on
|
|
781
|
+
// every Home visit spent one doomed round trip each time and filled the error log
|
|
782
|
+
// with something nobody can act on. Latch it once and stop asking; on a phone,
|
|
783
|
+
// where the call does work, this never trips.
|
|
784
|
+
if (isFeedSurfaceRefusal(error)) feedSurfaceRefused = true;
|
|
785
|
+
/* otherwise collapse silently, as before */
|
|
786
|
+
}
|
|
746
787
|
})());
|
|
747
788
|
}
|
|
748
789
|
await Promise.all(jobs);
|
|
@@ -893,6 +934,7 @@ function baseState(): State {
|
|
|
893
934
|
* let a stale failure clobber a newer success (returning `undefined` keeps the
|
|
894
935
|
* current service state; see JSRuntimeBootstrap.applyNext). */
|
|
895
936
|
let refreshGen = 0;
|
|
937
|
+
|
|
896
938
|
/** Last successful featured list — catch paths read this when the action's
|
|
897
939
|
* `state` snapshot was captured before a racing refresh painted products. */
|
|
898
940
|
let lastFeaturedProducts: ProductFeature[] = [];
|
|
@@ -18003,7 +18003,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
18003
18003
|
"open_url",
|
|
18004
18004
|
"calendar",
|
|
18005
18005
|
"share",
|
|
18006
|
-
"wix_cashier"
|
|
18006
|
+
"wix_cashier",
|
|
18007
|
+
"local_database"
|
|
18007
18008
|
],
|
|
18008
18009
|
"minBinaryVersion": "0.1.0",
|
|
18009
18010
|
"bundleVersion": "0.0.1"
|
|
@@ -19545,7 +19546,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
19545
19546
|
"contentType": "application/javascript+ts-bundle",
|
|
19546
19547
|
"declaredCapabilities": [
|
|
19547
19548
|
"wix_api",
|
|
19548
|
-
"share"
|
|
19549
|
+
"share",
|
|
19550
|
+
"local_database"
|
|
19549
19551
|
],
|
|
19550
19552
|
"minBinaryVersion": "0.1.0",
|
|
19551
19553
|
"bundleVersion": "0.0.1"
|