@wix/himalaya-cli 0.1567.0 → 0.1569.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/l10n/src/index.d.ts +9 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/message-format.d.ts +28 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/online-programs/src/index.d.ts +7 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/l10n.mjs +191 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-online-programs.mjs +14 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
- package/dist/cli.mjs +20994 -20822
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/app-config.md +10 -0
- package/guides/app-icon.md +20 -1
- package/guides/himi-json-output.md +7 -0
- package/guides/importable-sdks.md +1 -0
- package/guides/one-app-to-himi-app.md +14 -0
- package/guides/release-notes.md +6 -0
- package/guides/sdk-reference.json +41 -2
- package/guides/splash-screens.md +156 -5
- package/package.json +2 -2
- package/templates/beauty-salon/config.ts +12 -1
- package/templates/beauty-salon/dev/index.ts +265 -0
- package/templates/beauty-salon/himalaya.content.json +3 -0
- package/templates/beauty-salon/splash.json +3 -0
- package/templates/beauty-salon/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/beauty-salon/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/beauty-salon/tier5-src/himi-booking-service/index.ts +13 -9
- package/templates/beauty-salon/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/beauty-salon-owner/config.ts +8 -0
- package/templates/beauty-salon-owner/dev/index.ts +1 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/beauty-salon-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/branded-lite/config.ts +12 -1
- package/templates/branded-lite/dev/index.ts +299 -2
- package/templates/branded-lite/himalaya.content.json +3 -0
- package/templates/branded-lite/splash.json +3 -0
- package/templates/branded-lite/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/branded-lite/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/branded-lite/tier5-src/himi-booking-service/index.ts +13 -9
- package/templates/branded-lite/tier5-src/himi-branded-lite-group/index.ts +20 -3
- package/templates/branded-lite/tier5-src/himi-branded-lite-groups/index.ts +18 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifsettings/index.ts +4 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +124 -15
- package/templates/branded-lite/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/brandy/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/community-club/config.ts +12 -1
- package/templates/community-club/dev/index.ts +267 -1
- package/templates/community-club/himalaya.content.json +3 -0
- package/templates/community-club/splash.json +3 -0
- package/templates/community-club/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/community-club/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/community-club/tier5-src/himi-branded-lite-group/index.ts +20 -3
- package/templates/community-club/tier5-src/himi-branded-lite-groups/index.ts +18 -2
- package/templates/community-club/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/community-club/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/community-club-owner/config.ts +8 -0
- package/templates/community-club-owner/dev/index.ts +1 -0
- package/templates/community-club-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/community-club-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/events-meetups/config.ts +12 -1
- package/templates/events-meetups/dev/index.ts +267 -1
- package/templates/events-meetups/himalaya.content.json +3 -0
- package/templates/events-meetups/splash.json +3 -0
- package/templates/events-meetups/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/events-meetups/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/events-meetups/tier5-src/himi-branded-lite-group/index.ts +20 -3
- package/templates/events-meetups/tier5-src/himi-branded-lite-groups/index.ts +18 -2
- package/templates/events-meetups/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/events-meetups-owner/config.ts +8 -0
- package/templates/events-meetups-owner/dev/index.ts +1 -0
- package/templates/events-meetups-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/events-meetups-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/gym-fitness/config.ts +12 -1
- package/templates/gym-fitness/dev/index.ts +265 -0
- package/templates/gym-fitness/himalaya.content.json +3 -0
- package/templates/gym-fitness/splash.json +3 -0
- package/templates/gym-fitness/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/gym-fitness/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/gym-fitness/tier5-src/himi-booking-service/index.ts +13 -9
- package/templates/gym-fitness/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/gym-fitness-owner/config.ts +8 -0
- package/templates/gym-fitness-owner/dev/index.ts +1 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/gym-fitness-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/himi-chat/dev/index.ts +1 -0
- package/templates/himi-chat/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/nonprofit-cause/config.ts +12 -1
- package/templates/nonprofit-cause/dev/index.ts +267 -1
- package/templates/nonprofit-cause/himalaya.content.json +3 -0
- package/templates/nonprofit-cause/splash.json +3 -0
- package/templates/nonprofit-cause/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/nonprofit-cause/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group/index.ts +20 -3
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-groups/index.ts +18 -2
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/nonprofit-cause-owner/config.ts +8 -0
- package/templates/nonprofit-cause-owner/dev/index.ts +1 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/nonprofit-cause-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/owner-lite/config.ts +8 -0
- package/templates/owner-lite/dev/index.ts +1 -0
- package/templates/owner-lite/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/owner-lite/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/podcast-creator/config.ts +12 -1
- package/templates/podcast-creator/dev/index.ts +237 -0
- package/templates/podcast-creator/himalaya.content.json +3 -0
- package/templates/podcast-creator/splash.json +3 -0
- package/templates/podcast-creator/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/podcast-creator/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/podcast-creator-owner/config.ts +8 -0
- package/templates/podcast-creator-owner/dev/index.ts +1 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/podcast-creator-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/portfolio-creative/config.ts +12 -1
- package/templates/portfolio-creative/dev/index.ts +237 -0
- package/templates/portfolio-creative/himalaya.content.json +3 -0
- package/templates/portfolio-creative/splash.json +3 -0
- package/templates/portfolio-creative/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/portfolio-creative/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/portfolio-creative-owner/config.ts +8 -0
- package/templates/portfolio-creative-owner/dev/index.ts +1 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/portfolio-creative-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/restaurant/config.ts +12 -1
- package/templates/restaurant/dev/index.ts +237 -0
- package/templates/restaurant/himalaya.content.json +3 -0
- package/templates/restaurant/splash.json +3 -0
- package/templates/restaurant/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/restaurant/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/restaurant-owner/config.ts +8 -0
- package/templates/restaurant-owner/dev/index.ts +1 -0
- package/templates/restaurant-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/restaurant-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/retail-store/config.ts +12 -1
- package/templates/retail-store/dev/index.ts +237 -0
- package/templates/retail-store/himalaya.content.json +3 -0
- package/templates/retail-store/splash.json +3 -0
- package/templates/retail-store/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/retail-store/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/retail-store-owner/config.ts +8 -0
- package/templates/retail-store-owner/dev/index.ts +1 -0
- package/templates/retail-store-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/retail-store-owner/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/surface-showcase/dev/index.ts +1 -0
- package/templates/yoga-studio/config.ts +12 -1
- package/templates/yoga-studio/dev/index.ts +269 -1
- package/templates/yoga-studio/himalaya.content.json +3 -0
- package/templates/yoga-studio/splash.json +3 -0
- package/templates/yoga-studio/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/yoga-studio/tier5-src/_shared/rich-body.ts +44 -0
- package/templates/yoga-studio/tier5-src/himi-booking-service/index.ts +13 -9
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +124 -15
- package/templates/yoga-studio/tier5-src/himi-branded-lite-splash/index.ts +35 -0
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +4 -0
- package/templates/yoga-studio-owner/config.ts +8 -0
- package/templates/yoga-studio-owner/dev/index.ts +1 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/himi-copy.ts +17 -6
- package/templates/yoga-studio-owner/tier5-src/_shared/rich-body.ts +44 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Raw-descriptor dialect (see `himi docs tier-5-add-a-screen`); templated routes
|
|
3
3
|
// fill __HIMI_ID__ sentinels per request.
|
|
4
4
|
import config from "../config.js";
|
|
5
|
+
import splashIcon from "../splash.json" with { type: "json" };
|
|
5
6
|
|
|
6
7
|
const runtimeSetting = (value: unknown): unknown => {
|
|
7
8
|
if (value === "__HIMI_PODCAST_FEED_URL__") return process.env.PODCAST_FEED_URL?.trim() || "";
|
|
@@ -13,6 +14,227 @@ const runtimeSetting = (value: unknown): unknown => {
|
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
const SCREENS = runtimeSetting({
|
|
17
|
+
"himi_branded_splash": {
|
|
18
|
+
"screenId": "himi_branded_splash",
|
|
19
|
+
"renderer": "sdui_intent",
|
|
20
|
+
"title": "",
|
|
21
|
+
"schemaVersion": 1,
|
|
22
|
+
"cacheControl": {
|
|
23
|
+
"maxAge": 0,
|
|
24
|
+
"staleWhileRevalidate": 0
|
|
25
|
+
},
|
|
26
|
+
"input": {
|
|
27
|
+
"showIcon": true,
|
|
28
|
+
"title": "",
|
|
29
|
+
"caption": ""
|
|
30
|
+
},
|
|
31
|
+
"logicBundle": {
|
|
32
|
+
"url": "http://localhost:8190/v1/bundles/himi-branded-lite-splash?integrity=",
|
|
33
|
+
"integrity": "",
|
|
34
|
+
"contentType": "application/javascript+ts-bundle",
|
|
35
|
+
"declaredCapabilities": [],
|
|
36
|
+
"minBinaryVersion": "0.1.0",
|
|
37
|
+
"bundleVersion": "0.0.1"
|
|
38
|
+
},
|
|
39
|
+
"payload": {
|
|
40
|
+
"id": "splash_t5",
|
|
41
|
+
"body": {
|
|
42
|
+
"package": "himalaya",
|
|
43
|
+
"type": "ZStack",
|
|
44
|
+
"props": {
|
|
45
|
+
"alignment": "center",
|
|
46
|
+
"children": [
|
|
47
|
+
{
|
|
48
|
+
"id": "splash_t5_gradient",
|
|
49
|
+
"body": {
|
|
50
|
+
"package": "himalaya",
|
|
51
|
+
"type": "VStack",
|
|
52
|
+
"props": {
|
|
53
|
+
"children": [
|
|
54
|
+
{
|
|
55
|
+
"id": "splash_t5_gradient_fill",
|
|
56
|
+
"body": {
|
|
57
|
+
"package": "himalaya",
|
|
58
|
+
"type": "Spacer",
|
|
59
|
+
"props": {}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"modifiers": {
|
|
66
|
+
"fillMaxWidth": true,
|
|
67
|
+
"backgroundGradient": {
|
|
68
|
+
"token": "brand"
|
|
69
|
+
},
|
|
70
|
+
"transition": {
|
|
71
|
+
"enter": "fade",
|
|
72
|
+
"motion": {
|
|
73
|
+
"token": "appearSoft"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"respectReducedMotion": true
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": "splash_t5_icon",
|
|
81
|
+
"body": {
|
|
82
|
+
"package": "himalaya",
|
|
83
|
+
"type": "ZStack",
|
|
84
|
+
"props": {
|
|
85
|
+
"alignment": "center",
|
|
86
|
+
"children": [
|
|
87
|
+
{
|
|
88
|
+
"id": "splash_t5_icon_image",
|
|
89
|
+
"body": {
|
|
90
|
+
"package": "himalaya",
|
|
91
|
+
"type": "Image",
|
|
92
|
+
"props": {
|
|
93
|
+
"asset": "branded_lite_app_icon",
|
|
94
|
+
"width": 192,
|
|
95
|
+
"height": 192,
|
|
96
|
+
"contentMode": "fit"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"modifiers": {
|
|
100
|
+
"accessibilityRole": "decorative",
|
|
101
|
+
"scale": 1.5
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"modifiers": {
|
|
108
|
+
"width": 192,
|
|
109
|
+
"height": 192,
|
|
110
|
+
"clipShape": "circle",
|
|
111
|
+
"accessibilityRole": "decorative",
|
|
112
|
+
"hiddenPath": "$service:splash.iconHidden",
|
|
113
|
+
"transition": {
|
|
114
|
+
"enter": "none",
|
|
115
|
+
"exit": "fade",
|
|
116
|
+
"motion": {
|
|
117
|
+
"token": "appearSoft"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"respectReducedMotion": true
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "",
|
|
125
|
+
"body": {
|
|
126
|
+
"package": "himalaya",
|
|
127
|
+
"type": "VStack",
|
|
128
|
+
"props": {
|
|
129
|
+
"alignment": "center",
|
|
130
|
+
"spacing": 0,
|
|
131
|
+
"children": [
|
|
132
|
+
{
|
|
133
|
+
"id": "splash_t5_top",
|
|
134
|
+
"body": {
|
|
135
|
+
"package": "himalaya",
|
|
136
|
+
"type": "Spacer",
|
|
137
|
+
"props": {}
|
|
138
|
+
},
|
|
139
|
+
"modifiers": {
|
|
140
|
+
"weight": 1
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"id": "splash_t5_copy",
|
|
145
|
+
"body": {
|
|
146
|
+
"package": "himalaya",
|
|
147
|
+
"type": "VStack",
|
|
148
|
+
"props": {
|
|
149
|
+
"alignment": "center",
|
|
150
|
+
"spacing": 16,
|
|
151
|
+
"children": [
|
|
152
|
+
{
|
|
153
|
+
"id": "splash_t5_title",
|
|
154
|
+
"body": {
|
|
155
|
+
"package": "himalaya",
|
|
156
|
+
"type": "Text",
|
|
157
|
+
"props": {
|
|
158
|
+
"text": "$service:splash.title",
|
|
159
|
+
"style": "title1",
|
|
160
|
+
"color": "textOnAccent",
|
|
161
|
+
"textAlign": "center"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"id": "splash_t5_caption",
|
|
167
|
+
"body": {
|
|
168
|
+
"package": "himalaya",
|
|
169
|
+
"type": "Text",
|
|
170
|
+
"props": {
|
|
171
|
+
"text": "$service:splash.caption",
|
|
172
|
+
"style": "body",
|
|
173
|
+
"color": "textOnAccent",
|
|
174
|
+
"collapseWhenEmpty": true,
|
|
175
|
+
"textAlign": "center"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"id": "splash_t5_bottom",
|
|
181
|
+
"body": {
|
|
182
|
+
"package": "himalaya",
|
|
183
|
+
"type": "Spacer",
|
|
184
|
+
"props": {}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"modifiers": {
|
|
191
|
+
"weight": 1,
|
|
192
|
+
"fillMaxWidth": true,
|
|
193
|
+
"padding": {
|
|
194
|
+
"top": 120,
|
|
195
|
+
"bottom": 24,
|
|
196
|
+
"leading": 24,
|
|
197
|
+
"trailing": 24
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"id": "splash_t5_presented",
|
|
207
|
+
"body": {
|
|
208
|
+
"package": "himalaya",
|
|
209
|
+
"type": "Spacer",
|
|
210
|
+
"props": {}
|
|
211
|
+
},
|
|
212
|
+
"modifiers": {
|
|
213
|
+
"width": 0,
|
|
214
|
+
"height": 0,
|
|
215
|
+
"hiddenPath": "$service:splash.presentationPending",
|
|
216
|
+
"onAppear": {
|
|
217
|
+
"actionId": "splash.presented",
|
|
218
|
+
"params": {
|
|
219
|
+
"motion": "appearSoft"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"modifiers": {
|
|
228
|
+
"fillMaxWidth": true,
|
|
229
|
+
"onAppear": {
|
|
230
|
+
"actionId": "tier5.splash.present"
|
|
231
|
+
},
|
|
232
|
+
"background": {
|
|
233
|
+
"token": "accentPrimary"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
},
|
|
16
238
|
"himi_branded_home": {
|
|
17
239
|
"screenId": "himi_branded_home",
|
|
18
240
|
"renderer": "sdui_intent",
|
|
@@ -21483,6 +21705,21 @@ const SCREENS = runtimeSetting({
|
|
|
21483
21705
|
},
|
|
21484
21706
|
}) as Record<string, unknown>;
|
|
21485
21707
|
|
|
21708
|
+
// The hosted app icon is content: updating splash.json needs an OTA publish, not a native build.
|
|
21709
|
+
// Without a hosted image, preserve the bundled icon and its native handoff crop.
|
|
21710
|
+
if (splashIcon.iconUrl) {
|
|
21711
|
+
const url = new URL(splashIcon.iconUrl);
|
|
21712
|
+
if (url.protocol !== "https:" || url.username || url.password) throw new Error("Splash images require a public HTTPS URL");
|
|
21713
|
+
interface IconNode { id?: string; body: { package: string; type: string; props: { children?: IconNode[]; asset?: string; url?: string } } }
|
|
21714
|
+
const splash = SCREENS.himi_branded_splash as { input?: { customLogo?: boolean }; payload?: { body?: { props?: { children?: IconNode[] } } } };
|
|
21715
|
+
const icon = splash.payload?.body?.props?.children?.find((node) => node.id === "splash_t5_icon");
|
|
21716
|
+
const image = icon?.body.type === "ZStack" ? icon.body.props.children?.find((node) => node.id === "splash_t5_icon_image") : icon;
|
|
21717
|
+
if (image && !splash.input?.customLogo) {
|
|
21718
|
+
delete image.body.props.asset;
|
|
21719
|
+
image.body.props.url = splashIcon.iconUrl;
|
|
21720
|
+
}
|
|
21721
|
+
}
|
|
21722
|
+
|
|
21486
21723
|
// The language destination stays registered for deep links and future translations. Keep its
|
|
21487
21724
|
// account entry out of a single-language app; adding a locale to config.locale.translations
|
|
21488
21725
|
// makes the same entry visible after the app config reloads.
|
|
@@ -26013,6 +26250,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
26013
26250
|
}
|
|
26014
26251
|
}
|
|
26015
26252
|
},
|
|
26253
|
+
{
|
|
26254
|
+
"id": "himi_group.description_rich",
|
|
26255
|
+
"body": {
|
|
26256
|
+
"package": "himalaya",
|
|
26257
|
+
"type": "RichContent",
|
|
26258
|
+
"props": {
|
|
26259
|
+
"documentJsonPath": "$service:himiBrandedGroup.descriptionJson",
|
|
26260
|
+
"onLink": {
|
|
26261
|
+
"actionId": "tier5.himiBrandedGroup.openLink"
|
|
26262
|
+
},
|
|
26263
|
+
"fallback": {
|
|
26264
|
+
"id": "",
|
|
26265
|
+
"body": {
|
|
26266
|
+
"package": "himalaya",
|
|
26267
|
+
"type": "Text",
|
|
26268
|
+
"props": {
|
|
26269
|
+
"text": "$service:himiBrandedGroup.description",
|
|
26270
|
+
"style": "body",
|
|
26271
|
+
"color": "textSecondary"
|
|
26272
|
+
}
|
|
26273
|
+
}
|
|
26274
|
+
}
|
|
26275
|
+
}
|
|
26276
|
+
}
|
|
26277
|
+
},
|
|
26016
26278
|
{
|
|
26017
26279
|
"id": "",
|
|
26018
26280
|
"body": {
|
|
@@ -26024,6 +26286,9 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
26024
26286
|
"color": "textSecondary",
|
|
26025
26287
|
"collapseWhenEmpty": true
|
|
26026
26288
|
}
|
|
26289
|
+
},
|
|
26290
|
+
"modifiers": {
|
|
26291
|
+
"hiddenPath": "$service:himiBrandedGroup.hasDescriptionJson"
|
|
26027
26292
|
}
|
|
26028
26293
|
},
|
|
26029
26294
|
{
|
|
@@ -26166,7 +26431,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
26166
26431
|
"contentType": "application/javascript+ts-bundle",
|
|
26167
26432
|
"declaredCapabilities": [
|
|
26168
26433
|
"wix_api",
|
|
26169
|
-
"local_database"
|
|
26434
|
+
"local_database",
|
|
26435
|
+
"open_url"
|
|
26170
26436
|
],
|
|
26171
26437
|
"minBinaryVersion": "0.1.0",
|
|
26172
26438
|
"bundleVersion": "0.0.1"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Copy-as-configuration for WORKER-emitted strings (`himi docs designing-himi-screens`,
|
|
2
2
|
// §"Copy is configuration"): a worker never hardcodes user-facing copy — the
|
|
3
3
|
// descriptor bakes the provisioned copy-pack overrides relevant to this worker
|
|
4
|
-
// into its onAppear action params as a `copy` JSON object (
|
|
5
|
-
//
|
|
4
|
+
// into its onAppear action params as a `copy` JSON object (customer strings or
|
|
5
|
+
// source-matched stock translations, computed at descriptor-build time), and the
|
|
6
6
|
// worker reads every user-facing string through `copyParam(key, fallback)`.
|
|
7
7
|
//
|
|
8
8
|
// STASHED (the stashed appear-params idiom, himi-branded-lite-home): the
|
|
@@ -16,9 +16,13 @@
|
|
|
16
16
|
// every worker that emits user-facing copy, and copied verbatim into the
|
|
17
17
|
// generated templates' tier5-src/_shared/.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
/** Customer strings override every read; translated stock is valid only for its
|
|
20
|
+
* original English fallback. Some existing keys serve more than one message. */
|
|
21
|
+
export type CopyPackValue = string | { source: string; translation: string };
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
let stashedCopy: Record<string, CopyPackValue> = Object.create(null);
|
|
24
|
+
|
|
25
|
+
/** Absorb the `copy` onAppear param (customer strings or stock translation records)
|
|
22
26
|
* from an action arg. Call first in every action that can receive onAppear
|
|
23
27
|
* params (load/refresh). Non-copy args and malformed packs are ignored — the
|
|
24
28
|
* stock fallbacks keep rendering. */
|
|
@@ -29,9 +33,15 @@ export function stashCopy(arg: unknown): void {
|
|
|
29
33
|
try {
|
|
30
34
|
const parsed = JSON.parse(raw) as unknown;
|
|
31
35
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
32
|
-
const next: Record<string,
|
|
36
|
+
const next: Record<string, CopyPackValue> = Object.create(null);
|
|
33
37
|
for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
|
|
34
38
|
if (typeof value === "string") next[key] = value;
|
|
39
|
+
else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
40
|
+
const row = value as Record<string, unknown>;
|
|
41
|
+
if (typeof row.source === "string" && typeof row.translation === "string") {
|
|
42
|
+
next[key] = { source: row.source, translation: row.translation };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
35
45
|
}
|
|
36
46
|
stashedCopy = next;
|
|
37
47
|
} catch {
|
|
@@ -43,7 +53,8 @@ export function stashCopy(arg: unknown): void {
|
|
|
43
53
|
* pack / no such key reached this worker. */
|
|
44
54
|
export function copyParam(key: string, fallback: string): string {
|
|
45
55
|
const value = stashedCopy[key];
|
|
46
|
-
|
|
56
|
+
if (typeof value === "string") return value !== "" ? value : fallback;
|
|
57
|
+
return value?.source === fallback && value.translation !== "" ? value.translation : fallback;
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
/** Interpolate `{name}` placeholders in a (possibly overridden) template:
|
|
@@ -32,3 +32,47 @@ export function richBody(richContent: unknown, fallback = "", imageWidth = 1400)
|
|
|
32
32
|
const text = rejected === "too_deep" ? "" : ricosToPlainText(doc);
|
|
33
33
|
return { bodyJson: json, bodyText: text || fallback };
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
/** A Wix description may be Ricos (including serialized JSON), HTML or ordinary text.
|
|
37
|
+
* Keep rich documents on the existing bounded encoder path. Non-document JSON and
|
|
38
|
+
* clearly malformed serialization use an independent fallback. Ambiguous bracketed
|
|
39
|
+
* prose stays readable; this does not attempt to repair arbitrary JSON syntax. */
|
|
40
|
+
export function descriptionBody(value: unknown, fallback = "", imageWidth = 1400): RichBody {
|
|
41
|
+
if (typeof value !== "string") return richBody(value, fallback, imageWidth);
|
|
42
|
+
const text = value.trim();
|
|
43
|
+
if (/^[{[]/.test(text)) {
|
|
44
|
+
try {
|
|
45
|
+
const parsed: unknown = JSON.parse(text);
|
|
46
|
+
// Passing the parsed value avoids parsing a valid Ricos document twice; a
|
|
47
|
+
// different JSON structure is rejected by the same existing document check.
|
|
48
|
+
if (parsed && typeof parsed === "object") return richBody(parsed, fallback, imageWidth);
|
|
49
|
+
} catch {
|
|
50
|
+
const objectLike = /^\{\s*(?:["'}]|nodes\b)/.test(text);
|
|
51
|
+
// Only reject scalar-looking malformed arrays when their syntax is clearly
|
|
52
|
+
// unfinished (or contains JS's non-JSON `undefined`). Balanced bracketed
|
|
53
|
+
// prose such as "[1,000]" and "[12:30, 13:30]" is not JSON and stays readable.
|
|
54
|
+
const arrayTokens = text.replace(/"(?:\\.|[^"\\])*"/g, "")
|
|
55
|
+
.replace(/\b(?:true|false|null|undefined)\b/g, "")
|
|
56
|
+
.replace(/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/g, "");
|
|
57
|
+
const arrayLike = /^\[\s*[{"]/.test(text)
|
|
58
|
+
|| (text.startsWith("[") && /^[\s[\]{},:]*$/.test(arrayTokens)
|
|
59
|
+
&& (/,\s*]?$/.test(text) || /\bundefined\b/.test(text) || !text.endsWith("]")));
|
|
60
|
+
if (objectLike || arrayLike) return { bodyJson: "", bodyText: fallback };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Legacy HTML descriptions stay text. Preserve paragraph breaks and ordinary prose's
|
|
64
|
+
// bare '<' (e.g. "ages < 8"), without relying on browser-only DOM APIs in workers.
|
|
65
|
+
const plain = text
|
|
66
|
+
.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, "")
|
|
67
|
+
.replace(/<br\s*\/?\s*>/gi, "\n")
|
|
68
|
+
.replace(/<\/(?:p|div|h[1-6]|li)\s*>/gi, "\n\n")
|
|
69
|
+
.replace(/<\/?[a-z][^>]*>/gi, "")
|
|
70
|
+
.replace(/&(?:nbsp|amp|lt|gt|quot|apos|#39);/gi, (entity) => ({
|
|
71
|
+
" ": " ", "&": "&", "<": "<", ">": ">", """: '"', "'": "'", "'": "'",
|
|
72
|
+
})[entity.toLowerCase()] ?? entity)
|
|
73
|
+
.replace(/[\t\r ]+/g, " ")
|
|
74
|
+
.replace(/ *\n */g, "\n")
|
|
75
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
76
|
+
.trim();
|
|
77
|
+
return { bodyJson: "", bodyText: plain || fallback };
|
|
78
|
+
}
|
|
@@ -9,6 +9,8 @@ import { WIX_DETAIL_IMAGE } from "@himalaya/wix-media";
|
|
|
9
9
|
import { copyParam, stashCopy } from "../_shared/himi-copy.js";
|
|
10
10
|
import { get as dbGet, upsert as dbUpsert, type DbEntity } from "@himalaya/local-db";
|
|
11
11
|
import { isOfflineFailure, writeMayHaveLanded } from "../_shared/owner-load-error";
|
|
12
|
+
import { descriptionBody } from "../_shared/rich-body.js";
|
|
13
|
+
import { openRichLink } from "../_shared/rich-content-link.js";
|
|
12
14
|
|
|
13
15
|
interface MemberAvatar {
|
|
14
16
|
initials: string;
|
|
@@ -42,7 +44,8 @@ async function cachePutMembership(state: State, joined: boolean): Promise<void>
|
|
|
42
44
|
noImage: state.noImage,
|
|
43
45
|
detailScreenId: "himi_group",
|
|
44
46
|
};
|
|
45
|
-
await dbUpsert(ENTITY, { ...existing, id: state.id,
|
|
47
|
+
await dbUpsert(ENTITY, { ...existing, id: state.id, description: state.description,
|
|
48
|
+
descriptionJson: state.descriptionJson, joined: joined ? "true" : "false" });
|
|
46
49
|
} catch { /* capability not granted */ }
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -51,6 +54,8 @@ interface State {
|
|
|
51
54
|
id: string;
|
|
52
55
|
name: string;
|
|
53
56
|
description: string;
|
|
57
|
+
descriptionJson: string;
|
|
58
|
+
hasDescriptionJson: boolean;
|
|
54
59
|
privacy: string;
|
|
55
60
|
memberCount: string;
|
|
56
61
|
/** Member avatar strip (photo or initials per member) — best-effort: the
|
|
@@ -132,6 +137,8 @@ const initial: State = {
|
|
|
132
137
|
id: "",
|
|
133
138
|
name: "",
|
|
134
139
|
description: "",
|
|
140
|
+
descriptionJson: "",
|
|
141
|
+
hasDescriptionJson: false,
|
|
135
142
|
privacy: "",
|
|
136
143
|
memberCount: "",
|
|
137
144
|
memberAvatars: [],
|
|
@@ -162,6 +169,7 @@ const svc = defineService<State, {
|
|
|
162
169
|
load: (state: State, arg?: unknown) => Promise<State>;
|
|
163
170
|
join: (state: State) => Promise<State>;
|
|
164
171
|
leave: (state: State) => Promise<State>;
|
|
172
|
+
openLink: (state: State, arg?: unknown) => Promise<undefined>;
|
|
165
173
|
}>("himiBrandedGroup", {
|
|
166
174
|
state: initial,
|
|
167
175
|
actions: {
|
|
@@ -179,12 +187,16 @@ const svc = defineService<State, {
|
|
|
179
187
|
const privacyLabel = privacy[0].toUpperCase() + privacy.slice(1);
|
|
180
188
|
const signedIn = Boolean(await signedInEmail());
|
|
181
189
|
const memberAvatars = await memberAvatarsOf(id);
|
|
190
|
+
const body = descriptionBody(group.description, descriptionBody(group.teaser,
|
|
191
|
+
copyParam("group.descriptionFallback", "Join this group to connect with other members.")).bodyText);
|
|
182
192
|
const loaded: State = {
|
|
183
193
|
...state,
|
|
184
194
|
status: "ready",
|
|
185
195
|
id,
|
|
186
196
|
name,
|
|
187
|
-
description:
|
|
197
|
+
description: body.bodyText,
|
|
198
|
+
descriptionJson: body.bodyJson,
|
|
199
|
+
hasDescriptionJson: body.bodyJson !== "",
|
|
188
200
|
privacy: privacyLabel,
|
|
189
201
|
memberCount: count == null ? "" : `${count} ${count === 1 ? "member" : "members"}`,
|
|
190
202
|
memberAvatars,
|
|
@@ -209,12 +221,16 @@ const svc = defineService<State, {
|
|
|
209
221
|
const name = (String(cached.title ?? cached.name ?? "Group")).trim() || "Group";
|
|
210
222
|
const image = String(cached.image ?? "");
|
|
211
223
|
const signedIn = Boolean(await signedInEmail());
|
|
224
|
+
const body = descriptionBody(cached.descriptionJson || cached.description || cached.subtitle,
|
|
225
|
+
copyParam("group.descriptionFallback", "Join this group to connect with other members."));
|
|
212
226
|
const loaded: State = {
|
|
213
227
|
...state,
|
|
214
228
|
status: "ready",
|
|
215
229
|
id,
|
|
216
230
|
name,
|
|
217
|
-
description:
|
|
231
|
+
description: body.bodyText,
|
|
232
|
+
descriptionJson: body.bodyJson,
|
|
233
|
+
hasDescriptionJson: body.bodyJson !== "",
|
|
218
234
|
privacy: "Unknown",
|
|
219
235
|
memberCount: String(cached.meta ?? ""),
|
|
220
236
|
image,
|
|
@@ -233,6 +249,7 @@ const svc = defineService<State, {
|
|
|
233
249
|
return { ...state, id, status: "error", isLoading: false, notLoading: true, isErrored: true, notErrored: false, hideContent: true };
|
|
234
250
|
}
|
|
235
251
|
},
|
|
252
|
+
openLink: async (_state, arg) => { await openRichLink(arg); return undefined; },
|
|
236
253
|
join: async (state) => {
|
|
237
254
|
const signedIn = Boolean(await signedInEmail());
|
|
238
255
|
if (!signedIn) return membershipState({ ...state, message: copyParam("group.joinSignInMessage", "Sign in from Profile to join groups.") }, false, false);
|
|
@@ -3,6 +3,7 @@ import { queryGroups, type WixGroup } from "@himalaya/wix-groups";
|
|
|
3
3
|
import { groupImage } from "../_shared/himi-media.js";
|
|
4
4
|
import { copyParam, stashCopy } from "../_shared/himi-copy.js";
|
|
5
5
|
import { getAll, upsert, type DbEntity } from "@himalaya/local-db";
|
|
6
|
+
import { descriptionBody, ROW_IMAGE_WIDTH } from "../_shared/rich-body.js";
|
|
6
7
|
|
|
7
8
|
// Offline-first (data-offline): the groups list is a public read-through — paint the
|
|
8
9
|
// last-synced rows from the on-device store first (instant, works offline), then
|
|
@@ -13,7 +14,11 @@ import { getAll, upsert, type DbEntity } from "@himalaya/local-db";
|
|
|
13
14
|
// seam that keeps this shared bundle safe across every consuming app.
|
|
14
15
|
const ENTITY = "groups";
|
|
15
16
|
async function readCached(): Promise<GroupRow[]> {
|
|
16
|
-
try {
|
|
17
|
+
try {
|
|
18
|
+
const rows = (await getAll(ENTITY)) as unknown as GroupRow[];
|
|
19
|
+
return rows.map((row) => ({ ...row, subtitle: snippet(descriptionBody(row.subtitle).bodyText
|
|
20
|
+
|| descriptionBody(row.descriptionJson || row.description).bodyText) }));
|
|
21
|
+
} catch { return []; }
|
|
17
22
|
}
|
|
18
23
|
async function writeCached(rows: GroupRow[]): Promise<void> {
|
|
19
24
|
try { for (const r of rows) await upsert(ENTITY, r as unknown as DbEntity); } catch { /* capability not granted → online-only */ }
|
|
@@ -23,6 +28,8 @@ interface GroupRow {
|
|
|
23
28
|
id: string;
|
|
24
29
|
title: string;
|
|
25
30
|
subtitle: string;
|
|
31
|
+
description: string;
|
|
32
|
+
descriptionJson: string;
|
|
26
33
|
meta: string;
|
|
27
34
|
image: string;
|
|
28
35
|
initial: string;
|
|
@@ -45,14 +52,23 @@ interface State {
|
|
|
45
52
|
noEmpty: boolean;
|
|
46
53
|
}
|
|
47
54
|
|
|
55
|
+
function snippet(value: string): string {
|
|
56
|
+
const text = value.replace(/\s+/g, " ");
|
|
57
|
+
return text.length > 140 ? `${text.slice(0, 139).trimEnd()}…` : text;
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
function groupRow(group: WixGroup): GroupRow {
|
|
49
61
|
const title = (group.name || copyParam("groups.groupFallbackName", "Group")).trim();
|
|
50
62
|
const count = group.membersCount ?? group.memberCount;
|
|
51
63
|
const image = groupImage(group);
|
|
64
|
+
const teaser = descriptionBody(group.teaser).bodyText;
|
|
65
|
+
const body = descriptionBody(group.description, teaser, ROW_IMAGE_WIDTH);
|
|
52
66
|
return {
|
|
53
67
|
id: group.id || title,
|
|
54
68
|
title,
|
|
55
|
-
subtitle:
|
|
69
|
+
subtitle: snippet(teaser) || snippet(body.bodyText) || copyParam("groups.subtitleFallback", "Join the conversation."),
|
|
70
|
+
description: body.bodyText,
|
|
71
|
+
descriptionJson: body.bodyJson,
|
|
56
72
|
meta: count == null ? "" : `${count} ${count === 1 ? "member" : "members"}`,
|
|
57
73
|
image,
|
|
58
74
|
initial: (title[0] || "G").toUpperCase(),
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineService } from "@himalaya/state";
|
|
2
|
+
|
|
3
|
+
// Native renderers animate; this worker only publishes the requested visibility.
|
|
4
|
+
// The host waits for presentation, bounded by the original startup deadline.
|
|
5
|
+
const input = (globalThis as unknown as { himalaya?: { input?: Record<string, unknown> } }).himalaya?.input;
|
|
6
|
+
interface State {
|
|
7
|
+
title: string;
|
|
8
|
+
caption: string;
|
|
9
|
+
iconHidden: boolean;
|
|
10
|
+
presentationPending: boolean;
|
|
11
|
+
errorText?: string;
|
|
12
|
+
customLogoHidden?: boolean;
|
|
13
|
+
backgroundImageUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
export const splash = defineService<State, { present: (state: State) => State }>("splash", {
|
|
16
|
+
state: {
|
|
17
|
+
title: typeof input?.title === "string" ? input.title : "",
|
|
18
|
+
caption: typeof input?.caption === "string" ? input.caption : "",
|
|
19
|
+
iconHidden: false,
|
|
20
|
+
presentationPending: true,
|
|
21
|
+
// A malformed OTA toggle must not release the native cover as a successful
|
|
22
|
+
// presentation. The host's existing deadline remains the failure fallback.
|
|
23
|
+
...(input?.showIcon !== undefined && typeof input.showIcon !== "boolean"
|
|
24
|
+
? { errorText: "Splash showIcon must be a boolean" } : {}),
|
|
25
|
+
...(typeof input?.backgroundImageUrl === "string" ? { backgroundImageUrl: input.backgroundImageUrl } : {}),
|
|
26
|
+
...(input?.customLogo === true ? { customLogoHidden: true } : {}),
|
|
27
|
+
},
|
|
28
|
+
actions: {
|
|
29
|
+
present: (state) => state.errorText ? state : ({ ...state,
|
|
30
|
+
iconHidden: input?.showIcon === false || input?.customLogo === true,
|
|
31
|
+
...(input?.customLogo === true ? { customLogoHidden: input?.showIcon === false } : {}),
|
|
32
|
+
presentationPending: false,
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
});
|
|
@@ -19,6 +19,7 @@ import { createIapCommerce, onlineProgramOrders, pricingPlanOrders, storesAppleS
|
|
|
19
19
|
import { IAP_RESTORE_KEYS, NO_IAP_RESTORE, createIapRestore, resetUnhydratedKeysOnOlderRuntime, type IapRestoreFields } from "../_shared/iap-worker.js";
|
|
20
20
|
|
|
21
21
|
interface AuthRouteInput {
|
|
22
|
+
authContinuation?: string;
|
|
22
23
|
/** Standalone sign-in only: `register` opens the form on Create account. */
|
|
23
24
|
mode?: string;
|
|
24
25
|
intent?: string;
|
|
@@ -356,6 +357,9 @@ async function authenticate(s: S, operation: "signIn" | "register"): Promise<S |
|
|
|
356
357
|
await svc.beginAuth(); // publish busy before waiting for the network
|
|
357
358
|
const raw = await dispatch(operation === "signIn" ? "himi.wix.signInDirect" : "himi.wix.registerDirect", {
|
|
358
359
|
email: s.email.trim(), password,
|
|
360
|
+
// An opaque host-issued token, never a return route. Native commits it before the
|
|
361
|
+
// account change can destroy this worker; the replacement does not need this promise.
|
|
362
|
+
...(routeInput().authContinuation ? { authContinuation: routeInput().authContinuation } : {}),
|
|
359
363
|
...(operation === "register" ? { firstName: s.firstName, lastName: s.lastName } : {}),
|
|
360
364
|
});
|
|
361
365
|
rejectResult(raw, operation);
|
|
@@ -39,6 +39,14 @@ export default defineApp({
|
|
|
39
39
|
},
|
|
40
40
|
capabilities: ["live_activity","push","share","secure_storage","open_url","local_database","clipboard","ui","speech","camera","photos","file_picker","files","presigned_upload","app_info","biometrics","wix_platform","animation"],
|
|
41
41
|
designTokensPath: "./tokens.json",
|
|
42
|
+
// Native fallback; the T5 splash descriptor owns the editable launch appearance.
|
|
43
|
+
splash: {
|
|
44
|
+
"enabled": true,
|
|
45
|
+
"backgroundColor": "accentPrimary",
|
|
46
|
+
"caption": "Himalaya Owner",
|
|
47
|
+
"minVisibleMs": 400,
|
|
48
|
+
"maxHoldMs": 3000
|
|
49
|
+
},
|
|
42
50
|
navigation: {
|
|
43
51
|
"navKind": "responsive",
|
|
44
52
|
"surfaces": {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// fill __HIMI_ID__ sentinels per request.
|
|
4
4
|
import config from "../config.js";
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
const runtimeSetting = (value: unknown): unknown => {
|
|
7
8
|
if (value === "__HIMI_PODCAST_FEED_URL__") return process.env.PODCAST_FEED_URL?.trim() || "";
|
|
8
9
|
if (Array.isArray(value)) return value.map(runtimeSetting);
|