@wix/himalaya-cli 0.1303.0 → 0.1305.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1303.0",
3
+ "version": "0.1305.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": [
@@ -70,5 +70,5 @@
70
70
  "artifactId": "himalaya-cli"
71
71
  }
72
72
  },
73
- "falconPackageHash": "4ef9467b4cf9f72c791b0e318db771b01a5f56cb44ff4f6e46dd0e22"
73
+ "falconPackageHash": "1a8eace20ffd43d29d59275a5bc7dbb3382f8c21812d1cb32ec97037"
74
74
  }
@@ -639,9 +639,11 @@ export default defineApp({
639
639
  },
640
640
  {
641
641
  "screenId": "himi_photo_album",
642
- "isPublic": false,
642
+ "isPublic": true,
643
643
  "paramKeys": [
644
- "id"
644
+ "id",
645
+ "url",
646
+ "name"
645
647
  ],
646
648
  "parentScreenId": "himi_gallery",
647
649
  "tabId": ""
@@ -76632,7 +76632,10 @@ const SCREENS = runtimeSetting({
76632
76632
  "bottom": 28
76633
76633
  },
76634
76634
  "onAppear": {
76635
- "actionId": "tier5.himiBrandedGalleries.load"
76635
+ "actionId": "tier5.himiBrandedGalleries.load",
76636
+ "params": {
76637
+ "staticGalleries": "[]"
76638
+ }
76636
76639
  }
76637
76640
  }
76638
76641
  },
@@ -76641,7 +76644,8 @@ const SCREENS = runtimeSetting({
76641
76644
  "integrity": "",
76642
76645
  "contentType": "application/javascript+ts-bundle",
76643
76646
  "declaredCapabilities": [
76644
- "wix_api"
76647
+ "wix_api",
76648
+ "app_info"
76645
76649
  ],
76646
76650
  "minBinaryVersion": "0.1.0",
76647
76651
  "bundleVersion": "0.0.1"
@@ -76662,7 +76666,7 @@ const SCREENS = runtimeSetting({
76662
76666
  "package": "himalaya",
76663
76667
  "type": "VStack",
76664
76668
  "props": {
76665
- "spacing": 12,
76669
+ "spacing": 16,
76666
76670
  "alignment": "leading",
76667
76671
  "children": [
76668
76672
  {
@@ -76671,49 +76675,60 @@ const SCREENS = runtimeSetting({
76671
76675
  "package": "himalaya",
76672
76676
  "type": "VStack",
76673
76677
  "props": {
76674
- "spacing": 8,
76678
+ "spacing": 16,
76675
76679
  "alignment": "leading",
76676
76680
  "children": [
76677
76681
  {
76678
- "id": "himi_gallery.name",
76682
+ "id": "himi_gallery.title",
76679
76683
  "body": {
76680
76684
  "package": "himalaya",
76681
76685
  "type": "Text",
76682
76686
  "props": {
76683
- "text": "$service:himiBrandedSimpleDetail.name",
76687
+ "text": "$service:himiBrandedGalleries.galleryTitle",
76684
76688
  "style": "title1"
76685
76689
  }
76686
76690
  }
76687
76691
  },
76688
76692
  {
76689
- "id": "",
76693
+ "id": "himi_gallery.photos",
76690
76694
  "body": {
76691
76695
  "package": "himalaya",
76692
- "type": "Text",
76693
- "props": {
76694
- "text": "$service:himiBrandedSimpleDetail.subtitle",
76695
- "style": "body",
76696
- "color": "textSecondary",
76697
- "collapseWhenEmpty": true
76698
- }
76699
- }
76700
- },
76701
- {
76702
- "id": "himi_gallery.cta",
76703
- "body": {
76704
- "package": "himalaya",
76705
- "type": "Button",
76696
+ "type": "Grid",
76706
76697
  "props": {
76707
- "title": "Open album",
76708
- "style": "secondary",
76709
- "fullWidth": true,
76710
- "action": {
76711
- "actionId": "himi.open",
76712
- "params": {
76713
- "screenId": "himi_photo_album",
76714
- "id": "$service:himiBrandedSimpleDetail.id"
76698
+ "columns": 2,
76699
+ "columnsMedium": 3,
76700
+ "spacing": 10,
76701
+ "itemsPath": "$service:himiBrandedGalleries.photos",
76702
+ "items": [
76703
+ {
76704
+ "id": "",
76705
+ "body": {
76706
+ "package": "himalaya",
76707
+ "type": "Image",
76708
+ "props": {
76709
+ "url": "$item.url",
76710
+ "fillWidth": true,
76711
+ "height": 180,
76712
+ "contentMode": "fill",
76713
+ "contentDescription": "$item.title"
76714
+ }
76715
+ },
76716
+ "modifiers": {
76717
+ "cornerRadius": 8,
76718
+ "fillMaxWidth": true,
76719
+ "onTap": {
76720
+ "actionId": "himi.open",
76721
+ "params": {
76722
+ "screenId": "himi_photo_album",
76723
+ "id": "$item.id",
76724
+ "url": "$item.url",
76725
+ "name": "$item.title"
76726
+ }
76727
+ },
76728
+ "accessibilityLabel": "$item.title"
76729
+ }
76715
76730
  }
76716
- }
76731
+ ]
76717
76732
  }
76718
76733
  }
76719
76734
  },
@@ -76723,18 +76738,20 @@ const SCREENS = runtimeSetting({
76723
76738
  "package": "himalaya",
76724
76739
  "type": "Text",
76725
76740
  "props": {
76726
- "text": "$service:himiBrandedSimpleDetail.hint",
76727
- "style": "footnote",
76728
- "color": "textTertiary",
76729
- "collapseWhenEmpty": true
76741
+ "text": "Photos added to this album will appear here.",
76742
+ "style": "body",
76743
+ "color": "textSecondary"
76730
76744
  }
76745
+ },
76746
+ "modifiers": {
76747
+ "hiddenPath": "$service:himiBrandedGalleries.hasPhotos"
76731
76748
  }
76732
76749
  }
76733
76750
  ]
76734
76751
  }
76735
76752
  },
76736
76753
  "modifiers": {
76737
- "hiddenPath": "$service:himiBrandedSimpleDetail.noId"
76754
+ "hiddenPath": "$service:himiBrandedGalleries.noEntity"
76738
76755
  }
76739
76756
  },
76740
76757
  {
@@ -76758,7 +76775,7 @@ const SCREENS = runtimeSetting({
76758
76775
  }
76759
76776
  },
76760
76777
  "modifiers": {
76761
- "hiddenPath": "$service:himiBrandedSimpleDetail.hideLoading"
76778
+ "hiddenPath": "$service:himiBrandedGalleries.hideLoading"
76762
76779
  }
76763
76780
  },
76764
76781
  {
@@ -76773,7 +76790,7 @@ const SCREENS = runtimeSetting({
76773
76790
  }
76774
76791
  },
76775
76792
  "modifiers": {
76776
- "hiddenPath": "$service:himiBrandedSimpleDetail.hideLoadError"
76793
+ "hiddenPath": "$service:himiBrandedGalleries.hideLoadError"
76777
76794
  }
76778
76795
  },
76779
76796
  {
@@ -76791,7 +76808,7 @@ const SCREENS = runtimeSetting({
76791
76808
  "package": "himalaya",
76792
76809
  "type": "Icon",
76793
76810
  "props": {
76794
- "name": "search",
76811
+ "name": "photo",
76795
76812
  "size": 32,
76796
76813
  "tint": "textTertiary"
76797
76814
  }
@@ -76862,7 +76879,7 @@ const SCREENS = runtimeSetting({
76862
76879
  "bottom": 20
76863
76880
  },
76864
76881
  "fillMaxWidth": true,
76865
- "hiddenPath": "$service:himiBrandedSimpleDetail.hideNotFound"
76882
+ "hiddenPath": "$service:himiBrandedGalleries.hideNotFound"
76866
76883
  }
76867
76884
  }
76868
76885
  ]
@@ -76883,15 +76900,21 @@ const SCREENS = runtimeSetting({
76883
76900
  "bottom": 28
76884
76901
  },
76885
76902
  "onAppear": {
76886
- "actionId": "tier5.himiBrandedSimpleDetail.load"
76903
+ "actionId": "tier5.himiBrandedGalleries.open",
76904
+ "params": {
76905
+ "staticGalleries": "[]"
76906
+ }
76887
76907
  }
76888
76908
  }
76889
76909
  },
76890
76910
  "logicBundle": {
76891
- "url": "http://localhost:8190/v1/bundles/himi-branded-lite-simple-detail?integrity=",
76911
+ "url": "http://localhost:8190/v1/bundles/himi-branded-lite-galleries?integrity=",
76892
76912
  "integrity": "",
76893
76913
  "contentType": "application/javascript+ts-bundle",
76894
- "declaredCapabilities": [],
76914
+ "declaredCapabilities": [
76915
+ "wix_api",
76916
+ "app_info"
76917
+ ],
76895
76918
  "minBinaryVersion": "0.1.0",
76896
76919
  "bundleVersion": "0.0.1"
76897
76920
  }
@@ -76911,46 +76934,25 @@ const SCREENS = runtimeSetting({
76911
76934
  "package": "himalaya",
76912
76935
  "type": "VStack",
76913
76936
  "props": {
76914
- "spacing": 8,
76937
+ "spacing": 12,
76915
76938
  "alignment": "leading",
76916
76939
  "children": [
76917
76940
  {
76918
76941
  "id": "",
76919
76942
  "body": {
76920
76943
  "package": "himalaya",
76921
- "type": "VStack",
76944
+ "type": "Image",
76922
76945
  "props": {
76923
- "spacing": 8,
76924
- "alignment": "leading",
76925
- "children": [
76926
- {
76927
- "id": "himi_photo_album.title",
76928
- "body": {
76929
- "package": "himalaya",
76930
- "type": "Text",
76931
- "props": {
76932
- "text": "No photos yet",
76933
- "style": "title2"
76934
- }
76935
- }
76936
- },
76937
- {
76938
- "id": "",
76939
- "body": {
76940
- "package": "himalaya",
76941
- "type": "Text",
76942
- "props": {
76943
- "text": "Photos added to this album will appear here.",
76944
- "style": "body",
76945
- "color": "textSecondary"
76946
- }
76947
- }
76948
- }
76949
- ]
76946
+ "url": "$service:himiBrandedGalleries.photoUrl",
76947
+ "fillWidth": true,
76948
+ "height": 500,
76949
+ "contentMode": "fit",
76950
+ "contentDescription": "$service:himiBrandedGalleries.photoTitle"
76950
76951
  }
76951
76952
  },
76952
76953
  "modifiers": {
76953
- "hiddenPath": "$service:spacesPhotoAlbums.noEntity"
76954
+ "fillMaxWidth": true,
76955
+ "hiddenPath": "$service:himiBrandedGalleries.noEntity"
76954
76956
  }
76955
76957
  },
76956
76958
  {
@@ -76974,7 +76976,7 @@ const SCREENS = runtimeSetting({
76974
76976
  }
76975
76977
  },
76976
76978
  "modifiers": {
76977
- "hiddenPath": "$service:spacesPhotoAlbums.hideLoading"
76979
+ "hiddenPath": "$service:himiBrandedGalleries.hideLoading"
76978
76980
  }
76979
76981
  },
76980
76982
  {
@@ -76989,7 +76991,7 @@ const SCREENS = runtimeSetting({
76989
76991
  }
76990
76992
  },
76991
76993
  "modifiers": {
76992
- "hiddenPath": "$service:spacesPhotoAlbums.hideLoadError"
76994
+ "hiddenPath": "$service:himiBrandedGalleries.hideLoadError"
76993
76995
  }
76994
76996
  },
76995
76997
  {
@@ -77078,7 +77080,7 @@ const SCREENS = runtimeSetting({
77078
77080
  "bottom": 20
77079
77081
  },
77080
77082
  "fillMaxWidth": true,
77081
- "hiddenPath": "$service:spacesPhotoAlbums.hideNotFound"
77083
+ "hiddenPath": "$service:himiBrandedGalleries.hideNotFound"
77082
77084
  }
77083
77085
  }
77084
77086
  ]
@@ -77099,15 +77101,18 @@ const SCREENS = runtimeSetting({
77099
77101
  "bottom": 28
77100
77102
  },
77101
77103
  "onAppear": {
77102
- "actionId": "tier5.spacesPhotoAlbums.load"
77104
+ "actionId": "tier5.himiBrandedGalleries.view"
77103
77105
  }
77104
77106
  }
77105
77107
  },
77106
77108
  "logicBundle": {
77107
- "url": "http://localhost:8190/v1/bundles/wix-spaces-photo-albums?integrity=",
77109
+ "url": "http://localhost:8190/v1/bundles/himi-branded-lite-galleries?integrity=",
77108
77110
  "integrity": "",
77109
77111
  "contentType": "application/javascript+ts-bundle",
77110
- "declaredCapabilities": [],
77112
+ "declaredCapabilities": [
77113
+ "wix_api",
77114
+ "app_info"
77115
+ ],
77111
77116
  "minBinaryVersion": "0.1.0",
77112
77117
  "bundleVersion": "0.0.1"
77113
77118
  }
@@ -1,30 +1,32 @@
1
- // himi-branded-lite-galleries — branded-lite "Galleries" worker (Wix Pro Gallery).
1
+ // himi-branded-lite-galleries — branded-lite page galleries and Wix Pro Gallery.
2
2
  //
3
- // Like Videos, Wix Pro Gallery has NO platformized REST @wix/auto_sdk_* domain to
4
- // codegen — the real consumer app (wix-private/wix-one-app-pro-gallery) fetches it
5
- // from the photography one-app viewer REST endpoint. So this worker mirrors that: it
6
- // GETs the site's galleries from that endpoint through the raw wixApi bridge (absolute
7
- // URL + the app's WixApiCapability auth). a failed query is an error with
8
- // Retry (or Sign in), an empty one a real empty state; sample galleries appear only
9
- // in the host's explicit sample preview (_shared/branded-load-state.ts).
3
+ // Published Gallery page photos are carried by site analyze in the descriptor and
4
+ // displayed without a Pro Gallery request. Sites with no page gallery use the Wix
5
+ // API gateway. Failed reads remain errors; sample data is explicit preview only.
10
6
  //
11
- // Endpoint verbatim from wix-one-app-pro-gallery/src/constants (API_BASE_URL) +
12
- // api/photo-gallery-api.js (fetchGalleries).
13
7
  import { defineService } from "../_shared/collection-service.js";
8
+ import { get as getAppInfo } from "@himalaya/app-info";
14
9
  import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
10
+ import { presence, type PresenceFlags } from "../_shared/detail-presence.js";
15
11
 
16
- const GALLERIES_URL =
12
+ const GALLERIES_PATH = "/progallery/v2/galleries";
13
+ const LEGACY_GALLERIES_URL =
17
14
  "https://www.wix.com/_api/photography-one-app-viewer/galleries?itemsPerGallery=1&offset=0&limit=30&withHidden=false&useNew=true";
15
+ const PAGE_SIZE = 10; // API maximum. Keep the prior screen's 30-gallery cap.
16
+ const MAX_GALLERIES = 30;
18
17
 
19
18
  type WixApi = { call: (m: string, p: string, b?: unknown, h?: Record<string, string>) => Promise<unknown> };
20
19
  function wixApi(): WixApi | null {
21
20
  return (globalThis as { himalaya?: { wixApi?: WixApi } }).himalaya?.wixApi ?? null;
22
21
  }
23
22
 
24
- interface RawGallery { id?: string; name?: string; totalItemsCount?: number }
25
- interface Row { id: string; title: string; subtitle: string }
26
- interface S extends LoadFlags {
23
+ interface RawGallery { id: string; name?: string; totalItems?: number; totalItemsCount?: number }
24
+ interface StaticGallery { id: string; title: string; photos: string[] }
25
+ interface Row { id: string; title: string; subtitle: string; name: string; description: string; image: string; noCover: boolean }
26
+ interface PhotoRow { id: string; url: string; title: string }
27
+ interface S extends LoadFlags, PresenceFlags {
27
28
  galleries: Row[]; emptyText: string;
29
+ galleryTitle: string; photos: PhotoRow[]; photoUrl: string; photoTitle: string; noGallery: boolean; hasPhotos: boolean; hasPhoto: boolean; noPhoto: boolean;
28
30
  isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
29
31
  * shows only when the site really has none, and the unavailable one only when the
30
32
  * query failed. A failed query must never render the sentence that claims the
@@ -32,17 +34,93 @@ interface S extends LoadFlags {
32
34
  notMockEmpty: boolean; notMockUnavailable: boolean;
33
35
  }
34
36
 
37
+ function input(key: string): string {
38
+ const value = (globalThis as { himalaya?: { input?: Record<string, unknown> } }).himalaya?.input?.[key];
39
+ return typeof value === "string" ? value : "";
40
+ }
41
+
42
+ function parseStaticGalleries(raw: unknown): StaticGallery[] {
43
+ const parsed: unknown = typeof raw === "string" ? JSON.parse(raw) : raw;
44
+ if (parsed == null) return [];
45
+ if (!Array.isArray(parsed)) throw new Error("Malformed imported galleries");
46
+ let remaining = 50;
47
+ return parsed.slice(0, 10).flatMap((item): StaticGallery[] => {
48
+ if (!remaining) return [];
49
+ if (!item || typeof item !== "object") return [];
50
+ const gallery = item as Partial<StaticGallery>;
51
+ if (typeof gallery.id !== "string" || typeof gallery.title !== "string" || !Array.isArray(gallery.photos)) return [];
52
+ const photos = gallery.photos.filter((url): url is string => typeof url === "string" && /^https:\/\/static\.wixstatic\.com\/media\/[A-Za-z0-9_~.-]+$/.test(url)).slice(0, remaining);
53
+ remaining -= photos.length;
54
+ return photos.length ? [{ id: gallery.id, title: gallery.title, photos }] : [];
55
+ });
56
+ }
57
+
58
+ let staticGalleries: StaticGallery[] = [];
59
+
35
60
  function norm(g: RawGallery, i: number): Row {
36
61
  const title = (g.name || "").trim() || `Gallery ${i + 1}`;
37
- const n = g.totalItemsCount ?? 0;
62
+ const n = g.totalItems ?? g.totalItemsCount ?? 0;
38
63
  const subtitle = n ? (n === 1 ? "1 photo" : `${n} photos`) : "";
39
- return { id: g.id || `gallery-${i}`, title, subtitle };
64
+ return { id: g.id, title, subtitle, name: title, description: subtitle, image: "", noCover: true };
65
+ }
66
+
67
+ async function readGalleries(api: WixApi): Promise<RawGallery[]> {
68
+ const all: RawGallery[] = [];
69
+ for (let offset = 0; offset < MAX_GALLERIES; offset += PAGE_SIZE) {
70
+ const res = await api.call("GET", `${GALLERIES_PATH}?itemLimit=1&offset=${offset}&limit=${PAGE_SIZE}`) as unknown;
71
+ const page = (res as { galleries?: unknown } | null)?.galleries;
72
+ if (!Array.isArray(page) || page.some((g) => !g || typeof g.id !== "string" || !g.id)) {
73
+ throw new Error("Malformed Pro Gallery list response");
74
+ }
75
+ all.push(...page as RawGallery[]);
76
+ const total = (res as { totalGalleries?: unknown }).totalGalleries;
77
+ if (page.length < PAGE_SIZE || (typeof total === "number" && all.length >= total)) break;
78
+ }
79
+ return all;
80
+ }
81
+
82
+ async function readLegacyGalleries(api: WixApi): Promise<RawGallery[]> {
83
+ const res = await api.call("GET", LEGACY_GALLERIES_URL) as unknown;
84
+ const raw = Array.isArray(res) ? res :
85
+ (res as { galleries?: unknown; data?: { galleries?: unknown } } | null)?.galleries ??
86
+ (res as { data?: { galleries?: unknown } } | null)?.data?.galleries;
87
+ if (!Array.isArray(raw)) throw new Error("Malformed legacy Pro Gallery list response");
88
+ return raw.map((gallery, index) => {
89
+ if (!gallery || typeof gallery !== "object") throw new Error("Malformed legacy Pro Gallery row");
90
+ const row = gallery as Partial<RawGallery>;
91
+ return { ...row, id: typeof row.id === "string" && row.id ? row.id : `gallery-${index}` };
92
+ });
93
+ }
94
+
95
+ async function readCompatibleGalleries(api: WixApi): Promise<RawGallery[]> {
96
+ // The old absolute host is supported by native Wix transports, but the
97
+ // published web bridge refuses it as webwix_owner_only.
98
+ const nativeLegacyAvailable = async (): Promise<boolean> => {
99
+ const info = await getAppInfo().catch(() => undefined);
100
+ return info?.platform === "ios" || info?.platform === "android" ||
101
+ info?.platform === "macos" || info?.platform === "react-native";
102
+ };
103
+ try {
104
+ const galleries = await readGalleries(api);
105
+ if (galleries.length) return galleries;
106
+ if (!(await nativeLegacyAvailable())) return galleries;
107
+ // A native site's older Pro Gallery app can have content even when the gateway
108
+ // reports none. Keep the gateway's honest empty result if the old route is blocked.
109
+ try {
110
+ const legacy = await readLegacyGalleries(api);
111
+ return legacy.length ? legacy : galleries;
112
+ } catch { return galleries; }
113
+ } catch (gatewayError) {
114
+ if (!(await nativeLegacyAvailable())) throw gatewayError;
115
+ try { return await readLegacyGalleries(api); }
116
+ catch { throw gatewayError; }
117
+ }
40
118
  }
41
119
 
42
120
  const MOCK: Row[] = [
43
- { id: "sample-work", title: "Our Work", subtitle: "24 photos" },
44
- { id: "sample-events", title: "Events", subtitle: "48 photos" },
45
- { id: "sample-team", title: "The Team", subtitle: "9 photos" },
121
+ { id: "sample-work", title: "Our Work", subtitle: "24 photos", name: "Our Work", description: "24 photos", image: "", noCover: true },
122
+ { id: "sample-events", title: "Events", subtitle: "48 photos", name: "Events", description: "48 photos", image: "", noCover: true },
123
+ { id: "sample-team", title: "The Team", subtitle: "9 photos", name: "The Team", description: "9 photos", image: "", noCover: true },
46
124
  ];
47
125
 
48
126
  /** sample rows reach the screen ONLY in the host's explicit sample preview;
@@ -55,27 +133,58 @@ const COPY: LoadCopy<Row> = {
55
133
  sample: () => MOCK.map((r) => ({ ...r })),
56
134
  };
57
135
 
58
- const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedGalleries", {
59
- state: { ...LOADING, galleries: [], emptyText: "" },
136
+ const svc = defineService<S, {
137
+ load: (s: S, arg?: { staticGalleries?: unknown }) => Promise<S>;
138
+ open: (s: S, arg?: { staticGalleries?: unknown }) => S;
139
+ view: (s: S) => S;
140
+ }>("himiBrandedGalleries", {
141
+ state: { ...LOADING, ...presence("loading"), galleries: [], emptyText: "", galleryTitle: "", photos: [], photoUrl: "", photoTitle: "", noGallery: true, hasPhotos: false, hasPhoto: false, noPhoto: true },
60
142
  actions: {
61
- load: async (s) => {
143
+ load: async (s, arg) => {
62
144
  try {
145
+ if (arg && "staticGalleries" in arg) {
146
+ staticGalleries = [];
147
+ staticGalleries = parseStaticGalleries(arg.staticGalleries);
148
+ }
149
+ if (staticGalleries.length) {
150
+ const rows = staticGalleries.map((gallery) => {
151
+ const subtitle = gallery.photos.length === 1 ? "1 photo" : `${gallery.photos.length} photos`;
152
+ return { id: gallery.id, title: gallery.title, subtitle, name: gallery.title, description: subtitle, image: gallery.photos[0], noCover: false };
153
+ });
154
+ return { ...s, ...loaded("galleries", rows, COPY) };
155
+ }
63
156
  const api = wixApi();
64
157
  if (!api) return { ...s, ...loadFailed("galleries", new Error("Wix bridge unavailable"), COPY) };
65
- const res = (await api.call("GET", GALLERIES_URL)) as
66
- { galleries?: RawGallery[] } | RawGallery[] | { data?: { galleries?: RawGallery[] } };
67
- // Accept {galleries:[...]}, a top-level array, or a {data:{galleries}} envelope.
68
- const raw: RawGallery[] =
69
- (res as { galleries?: RawGallery[] })?.galleries ??
70
- (Array.isArray(res) ? (res as RawGallery[]) : undefined) ??
71
- (res as { data?: { galleries?: RawGallery[] } })?.data?.galleries ?? [];
158
+ const raw = await readCompatibleGalleries(api);
72
159
  const galleries = raw.map(norm);
73
160
  return { ...s, ...loaded("galleries", galleries, COPY) };
74
161
  } catch (err) {
75
162
  return { ...s, ...loadFailed("galleries", err, COPY) };
76
163
  }
77
164
  },
165
+ open: (s, arg) => {
166
+ try {
167
+ if (arg && "staticGalleries" in arg) {
168
+ staticGalleries = [];
169
+ staticGalleries = parseStaticGalleries(arg.staticGalleries);
170
+ }
171
+ } catch (err) {
172
+ return { ...s, ...loadFailed("galleries", err, COPY), ...presence("failed"), galleryTitle: "", photos: [],
173
+ noGallery: true, hasPhotos: false, photoUrl: "", photoTitle: "", hasPhoto: false, noPhoto: true };
174
+ }
175
+ const id = input("id");
176
+ const gallery = staticGalleries.find((entry) => entry.id === id);
177
+ const missing = !id || (staticGalleries.length > 0 && !gallery);
178
+ return { ...s, ...loaded("galleries", s.galleries, COPY), ...presence(missing ? "missing" : "found"), galleryTitle: gallery?.title || input("name"),
179
+ photos: (gallery?.photos ?? []).map((url, index) => ({ id: `${id}-${index}`, url, title: `Photo ${index + 1}` })),
180
+ noGallery: missing, hasPhotos: !!gallery?.photos.length, noPhoto: true };
181
+ },
182
+ view: (s) => {
183
+ const photoUrl = input("url");
184
+ const valid = /^https:\/\/static\.wixstatic\.com\/media\/[A-Za-z0-9_~.-]+$/.test(photoUrl);
185
+ return { ...s, ...loaded("galleries", s.galleries, COPY), ...presence(valid ? "found" : "missing"),
186
+ photoUrl: valid ? photoUrl : "", photoTitle: valid ? input("name") || "Gallery photo" : "", hasPhoto: valid, noPhoto: !valid };
187
+ },
78
188
  },
79
189
  });
80
- svc.load();
81
190
  export { svc };
@@ -1,21 +0,0 @@
1
- // Tier-5 bundle: Wix Spaces clone — Photo Albums (ON-DEVICE, site-scoped).
2
- // No albums API wired yet → renders the real empty state, never fabricated rows.
3
- // The emptyTitle/emptyBody copy is the Spaces clone's LIST screen. An app that opens
4
- // this for ONE album (branded-lite's gallery "Open album", which passes the album id)
5
- // renders its own single-album copy and gates it on `noEntity`; opened with no id at
6
- // all it shows the shared not-found state.
7
- import { defineService } from "@himalaya/state";
8
- import { presence, detailInputId, type PresenceFlags } from "../_shared/detail-presence.js";
9
-
10
- interface S extends PresenceFlags { status: "ready"; emptyTitle: string; emptyBody: string }
11
-
12
- const svc = defineService<S, { load: (s: S) => S }>("spacesPhotoAlbums", {
13
- state: {
14
- status: "ready",
15
- emptyTitle: "No albums yet",
16
- emptyBody: "Photo albums shared on this site will appear here.",
17
- ...presence("loading"),
18
- },
19
- actions: { load: (s) => ({ ...s, ...presence(detailInputId() ? "found" : "missing") }) },
20
- });
21
- export { svc };