@wix/himalaya-cli 0.1438.0 → 0.1440.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/ui/src/index.d.ts +7 -4
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/ui.mjs +2 -2
  3. package/dist/cli.mjs +434 -106
  4. package/dist/preview-assets.generated.bin +0 -0
  5. package/guides/designing-himi-screens.md +5 -1
  6. package/guides/hhp.md +13 -1
  7. package/guides/sdk-reference.json +3 -3
  8. package/guides/tier-5-add-a-screen.md +11 -0
  9. package/package.json +2 -2
  10. package/templates/beauty-salon/dev/index.ts +1 -90
  11. package/templates/beauty-salon/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  12. package/templates/branded-lite/dev/index.ts +1 -90
  13. package/templates/branded-lite/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  14. package/templates/community-club/dev/index.ts +1 -90
  15. package/templates/community-club/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  16. package/templates/events-meetups/dev/index.ts +1 -90
  17. package/templates/events-meetups/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  18. package/templates/gym-fitness/dev/index.ts +1 -90
  19. package/templates/gym-fitness/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  20. package/templates/nonprofit-cause/dev/index.ts +1 -90
  21. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  22. package/templates/podcast-creator/dev/index.ts +1 -90
  23. package/templates/podcast-creator/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  24. package/templates/portfolio-creative/dev/index.ts +1 -90
  25. package/templates/portfolio-creative/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  26. package/templates/restaurant/dev/index.ts +1 -90
  27. package/templates/restaurant/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  28. package/templates/retail-store/dev/index.ts +1 -90
  29. package/templates/retail-store/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
  30. package/templates/yoga-studio/dev/index.ts +1 -90
  31. package/templates/yoga-studio/tier5-src/himi-branded-lite-account-settings/index.ts +4 -1
Binary file
@@ -252,7 +252,11 @@ scroll. *Reach for `SegmentedControl` for 2–4 in-content modes; `Tabs`/tab-bar
252
252
  **Feedback & overlays** — `Banner` for a persistent inline message (with a retry action on error);
253
253
  `Snackbar` for a transient confirmation; `AlertDialog` for a blocking decision; `BottomSheet` for
254
254
  contextual actions/detail; `Tooltip`/`Popover` for a small anchored hint. *Reach for `Snackbar`, not
255
- `AlertDialog`, to confirm a completed action — don't block on success.*
255
+ `AlertDialog`, to confirm a completed action — don't block on success.* The `Snackbar` COMPONENT draws
256
+ inline where you place it; for a transient toast that floats at the bottom of the screen — an app
257
+ error after a failed action, say — use the `snackbar` presentation verb or `ui.snackbar({ message,
258
+ tone: "danger" })` from a worker: it floats above the tab bar, animates in and out, queues, honours
259
+ `durationMs`, and is announced to screen readers on every platform.
256
260
 
257
261
  **Status & data-viz** — `Badge`/`Tag`/`Chip` for compact labels; `Rating` for stars (`size: "sm"` in a
258
262
  dense row); `ProgressBar` for determinate progress, `ActivityIndicator` for indeterminate; `Gauge` for
package/guides/hhp.md CHANGED
@@ -54,11 +54,15 @@ payloads retain native fields and normalize selection values into `event.value`.
54
54
  Nested scalar paths are checked and updated immutably. Two-way value binding owns
55
55
  the component's change callback. Explicit `on:change` is used for custom reducers.
56
56
  Boolean `bind:hidden` and existing declared property bindings are available.
57
+ `bind:error` on a text field takes **string** state: the error message, where an
58
+ empty string means valid (a boolean flag is a lint error).
57
59
  Read-only controls such as Gauge and ActivityIndicator accept one-way value
58
60
  bindings without generating a change action.
59
61
 
60
62
  Keyed lists use `each="items" key="id"` on a Grid/LazyList and one row template.
61
- Initial items require unique string ids. Row text uses `{{$item.title}}`. Compute
63
+ Initial items require unique string ids. Row text uses `{{$item.title}}`; mixed
64
+ row text such as `“{{$item.text}}”` is projected by the controller. `$item` bindings
65
+ are typed from the initial rows: `bind:hidden="$item.done"` needs a boolean field. Compute
62
66
  expressions in controllers; interpolation accepts paths, not executable expressions.
63
67
  Direct `application/himalaya-service` scripts retain `defineService` authoring.
64
68
 
@@ -76,6 +80,14 @@ props; `slot="primary"` and `slot="detail"` supply SplitView slots. Structured p
76
80
  use a child `script type="application/himalaya-props"` containing JSON.
77
81
  `on:<native-action-property>` exposes declared events; click/change/submit have
78
82
  ordinary-control aliases. Explicit modifiers use `data-mod-*` or `himi-mod-*`.
83
+ A `…-path` modifier (`data-mod-hidden-path="full"`, `data-mod-background-color-path`)
84
+ names controller state exactly like `bind:*`, or `$item.<field>` in a row; an unknown
85
+ path is a lint error. `onMeasure` keys name the renderer's measure store instead.
86
+ `style` and `title` are HTML globals: `style` is always CSS, so a native `style`
87
+ variant uses `variant="primary"`; `title="…"` sets a component's `title` field. CSS
88
+ `font` applies only to text components (Text, Label, Marquee). The profile's
89
+ handler list holds only router actions every renderer implements (`himi.open`);
90
+ tab switching from content is not supported yet.
79
91
 
80
92
  The profile is the intersection of enabled deployment surfaces. It retains field
81
93
  eligibility and reports web support independently. Placeholder renderer cases,
@@ -4715,19 +4715,19 @@
4715
4715
  {
4716
4716
  "name": "SnackbarTone",
4717
4717
  "kind": "type",
4718
- "jsdoc": "/** Snackbar tone — maps to the app's tone background tokens. */",
4718
+ "jsdoc": "/** Snackbar tone — maps to the app's tone background tokens (`info` → textPrimary, `success`,\n * `warning`, `danger`). Use `danger` for errors; the hosts also accept `error` as an alias of it. */",
4719
4719
  "decl": "export type SnackbarTone = \"info\" | \"success\" | \"warning\" | \"danger\";"
4720
4720
  },
4721
4721
  {
4722
4722
  "name": "SnackbarOptions",
4723
4723
  "kind": "interface",
4724
4724
  "jsdoc": "",
4725
- "decl": "export interface SnackbarOptions {\n message: string;\n /** Default \"info\". */\n tone?: SnackbarTone;\n /** Auto-dismiss delay. Default 3000. Ignored on web (fixed-duration there). */\n durationMs?: number;\n}"
4725
+ "decl": "export interface SnackbarOptions {\n message: string;\n /** Default \"info\". */\n tone?: SnackbarTone;\n /** Auto-dismiss delay in ms, on every host. Default 3000; 0 or less also means 3000. */\n durationMs?: number;\n}"
4726
4726
  },
4727
4727
  {
4728
4728
  "name": "snackbar",
4729
4729
  "kind": "function",
4730
- "jsdoc": "/** Show a transient snackbar toast. Resolves once it is PRESENTED (not after it\n * auto-dismisses). Rejects with `no_ui_host` if no presenter is attached. */",
4730
+ "jsdoc": "/** Show a transient snackbar toast: it floats above the tab bar, slides and fades in and out\n * (fades only under reduced motion), queues behind one that is already showing, and is read\n * by VoiceOver / TalkBack. Resolves once it is PRESENTED (not after it auto-dismisses).\n * Rejects with `no_ui_host` if no presenter is attached. */",
4731
4731
  "decl": "export async function snackbar(options: SnackbarOptions): Promise<void>;"
4732
4732
  },
4733
4733
  {
@@ -479,6 +479,17 @@ This is what makes the fail-closed capability gates readable. `local_database: e
479
479
  "X" is not declared in the app's dataSchema` is a message written to be read — before
480
480
  #2288 an author only ever saw an eternal spinner.
481
481
 
482
+ **A persisted snapshot only hydrates the bundle that wrote it.** The cold-boot
483
+ snapshot is stamped with the writing bundle's integrity hash (a reserved
484
+ `__himalaya_snapshot` key beside the services) and restored only into that exact bundle.
485
+ Ship a new bundle and the first cold boot starts every service from its declared `state`;
486
+ the old snapshot is deleted and reported once per service as `worker_state_discarded`
487
+ (`{ service, reason: "bundle_mismatch" | "unstamped", bundleHash, storedBundleHash }`).
488
+ Snapshots written before stamping existed count as `unstamped`, which also means they are
489
+ dropped once. So you never have to defend a reducer against last release's state shape —
490
+ but a bundle change costs one cold boot of last-known content. Carrying state across bundle
491
+ versions (`stateVersion` + `migrate`) is not supported yet.
492
+
482
493
  ### Show App Store prices for catalog items
483
494
 
484
495
  A screen that shows or sells a program, product or plan that may be an App Store in-app purchase
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1438.0",
3
+ "version": "0.1440.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -71,5 +71,5 @@
71
71
  "artifactId": "himalaya-cli"
72
72
  }
73
73
  },
74
- "falconPackageHash": "ecadfa529dda6d1f49570340c04988f711cb239a5209ce8c69e31e86"
74
+ "falconPackageHash": "99935bae3ae7704f52450cbbbd84c04eb179c2bc315f759898441180"
75
75
  }
@@ -3691,7 +3691,7 @@ const SCREENS = runtimeSetting({
3691
3691
  "onTap": {
3692
3692
  "actionId": "himi.open",
3693
3693
  "params": {
3694
- "screenId": "himi_view_profile"
3694
+ "screenId": "himi_account_settings"
3695
3695
  }
3696
3696
  },
3697
3697
  "pressFeedback": "scale",
@@ -3773,95 +3773,6 @@ const SCREENS = runtimeSetting({
3773
3773
  "hiddenPath": "$service:himiStoreAccount.notMember"
3774
3774
  }
3775
3775
  },
3776
- {
3777
- "id": "himi_account.settings",
3778
- "body": {
3779
- "package": "himalaya",
3780
- "type": "HStack",
3781
- "props": {
3782
- "spacing": 12,
3783
- "children": [
3784
- {
3785
- "id": "",
3786
- "body": {
3787
- "package": "himalaya",
3788
- "type": "Icon",
3789
- "props": {
3790
- "name": "settings",
3791
- "size": 18,
3792
- "tint": "accentPrimary"
3793
- }
3794
- },
3795
- "modifiers": {
3796
- "accessibilityRole": "decorative"
3797
- }
3798
- },
3799
- {
3800
- "id": "",
3801
- "body": {
3802
- "package": "himalaya",
3803
- "type": "Text",
3804
- "props": {
3805
- "text": "My Account",
3806
- "style": "bodyEmphasis"
3807
- }
3808
- }
3809
- },
3810
- {
3811
- "id": "",
3812
- "body": {
3813
- "package": "himalaya",
3814
- "type": "Spacer",
3815
- "props": {}
3816
- }
3817
- },
3818
- {
3819
- "id": "",
3820
- "body": {
3821
- "package": "himalaya",
3822
- "type": "Icon",
3823
- "props": {
3824
- "name": "chevron_right",
3825
- "size": 16,
3826
- "tint": "textTertiary"
3827
- }
3828
- },
3829
- "modifiers": {
3830
- "accessibilityRole": "decorative"
3831
- }
3832
- }
3833
- ]
3834
- }
3835
- },
3836
- "modifiers": {
3837
- "background": {
3838
- "token": "surfaceElevated"
3839
- },
3840
- "border": {
3841
- "width": 1,
3842
- "color": {
3843
- "token": "border"
3844
- }
3845
- },
3846
- "cornerRadius": 8,
3847
- "padding": {
3848
- "leading": 14,
3849
- "trailing": 14,
3850
- "top": 13,
3851
- "bottom": 13
3852
- },
3853
- "onTap": {
3854
- "actionId": "himi.open",
3855
- "params": {
3856
- "screenId": "himi_account_settings"
3857
- }
3858
- },
3859
- "pressFeedback": "scale",
3860
- "haptic": "light",
3861
- "accessibilityLabel": "My Account",
3862
- "hiddenPath": "$service:himiStoreAccount.notMember"
3863
- }
3864
- },
3865
3776
  {
3866
3777
  "id": "himi_account.subscriptions_guest",
3867
3778
  "body": {
@@ -9,7 +9,7 @@ import { generateMemberPhotoUploadUrl } from "@himalaya/wix-site-media";
9
9
  import { memberAccess } from "../_shared/member-access.js";
10
10
  import { memberAccountRoutes } from "../_shared/member-account-routes.js";
11
11
  import { copyParam, stashCopy } from "../_shared/himi-copy.js";
12
- import "./blocked-members.js";
12
+ import { svc as blockedMembers } from "./blocked-members.js";
13
13
 
14
14
  interface ProfileValues {
15
15
  displayName: string;
@@ -641,6 +641,9 @@ const svc = defineService<S, {
641
641
  const version = ++accountLoadVersion;
642
642
  photoUploadVersion += 1;
643
643
  stashCopy(arg);
644
+ // The blocked-members section also loads from its own nested onAppear on a device; starting it
645
+ // here too makes the root onAppear — the only one `himi test` fires — settle it. Re-entry-guarded.
646
+ void blockedMembers.load(arg).catch(() => undefined);
644
647
  try {
645
648
  const { email, scope, siteUrl, member } = await fetchMember((arg as { siteUrl?: unknown } | undefined)?.siteUrl);
646
649
  const current = await memberAccess();
@@ -5033,7 +5033,7 @@ const SCREENS = runtimeSetting({
5033
5033
  "onTap": {
5034
5034
  "actionId": "himi.open",
5035
5035
  "params": {
5036
- "screenId": "himi_view_profile"
5036
+ "screenId": "himi_account_settings"
5037
5037
  }
5038
5038
  },
5039
5039
  "pressFeedback": "scale",
@@ -5115,95 +5115,6 @@ const SCREENS = runtimeSetting({
5115
5115
  "hiddenPath": "$service:himiStoreAccount.notMember"
5116
5116
  }
5117
5117
  },
5118
- {
5119
- "id": "himi_account.settings",
5120
- "body": {
5121
- "package": "himalaya",
5122
- "type": "HStack",
5123
- "props": {
5124
- "spacing": 12,
5125
- "children": [
5126
- {
5127
- "id": "",
5128
- "body": {
5129
- "package": "himalaya",
5130
- "type": "Icon",
5131
- "props": {
5132
- "name": "settings",
5133
- "size": 18,
5134
- "tint": "accentPrimary"
5135
- }
5136
- },
5137
- "modifiers": {
5138
- "accessibilityRole": "decorative"
5139
- }
5140
- },
5141
- {
5142
- "id": "",
5143
- "body": {
5144
- "package": "himalaya",
5145
- "type": "Text",
5146
- "props": {
5147
- "text": "My Account",
5148
- "style": "bodyEmphasis"
5149
- }
5150
- }
5151
- },
5152
- {
5153
- "id": "",
5154
- "body": {
5155
- "package": "himalaya",
5156
- "type": "Spacer",
5157
- "props": {}
5158
- }
5159
- },
5160
- {
5161
- "id": "",
5162
- "body": {
5163
- "package": "himalaya",
5164
- "type": "Icon",
5165
- "props": {
5166
- "name": "chevron_right",
5167
- "size": 16,
5168
- "tint": "textTertiary"
5169
- }
5170
- },
5171
- "modifiers": {
5172
- "accessibilityRole": "decorative"
5173
- }
5174
- }
5175
- ]
5176
- }
5177
- },
5178
- "modifiers": {
5179
- "background": {
5180
- "token": "surfaceElevated"
5181
- },
5182
- "border": {
5183
- "width": 1,
5184
- "color": {
5185
- "token": "border"
5186
- }
5187
- },
5188
- "cornerRadius": 8,
5189
- "padding": {
5190
- "leading": 14,
5191
- "trailing": 14,
5192
- "top": 13,
5193
- "bottom": 13
5194
- },
5195
- "onTap": {
5196
- "actionId": "himi.open",
5197
- "params": {
5198
- "screenId": "himi_account_settings"
5199
- }
5200
- },
5201
- "pressFeedback": "scale",
5202
- "haptic": "light",
5203
- "accessibilityLabel": "My Account",
5204
- "hiddenPath": "$service:himiStoreAccount.notMember"
5205
- }
5206
- },
5207
5118
  {
5208
5119
  "id": "himi_account.subscriptions_guest",
5209
5120
  "body": {
@@ -9,7 +9,7 @@ import { generateMemberPhotoUploadUrl } from "@himalaya/wix-site-media";
9
9
  import { memberAccess } from "../_shared/member-access.js";
10
10
  import { memberAccountRoutes } from "../_shared/member-account-routes.js";
11
11
  import { copyParam, stashCopy } from "../_shared/himi-copy.js";
12
- import "./blocked-members.js";
12
+ import { svc as blockedMembers } from "./blocked-members.js";
13
13
 
14
14
  interface ProfileValues {
15
15
  displayName: string;
@@ -641,6 +641,9 @@ const svc = defineService<S, {
641
641
  const version = ++accountLoadVersion;
642
642
  photoUploadVersion += 1;
643
643
  stashCopy(arg);
644
+ // The blocked-members section also loads from its own nested onAppear on a device; starting it
645
+ // here too makes the root onAppear — the only one `himi test` fires — settle it. Re-entry-guarded.
646
+ void blockedMembers.load(arg).catch(() => undefined);
644
647
  try {
645
648
  const { email, scope, siteUrl, member } = await fetchMember((arg as { siteUrl?: unknown } | undefined)?.siteUrl);
646
649
  const current = await memberAccess();
@@ -2875,7 +2875,7 @@ const SCREENS = runtimeSetting({
2875
2875
  "onTap": {
2876
2876
  "actionId": "himi.open",
2877
2877
  "params": {
2878
- "screenId": "himi_view_profile"
2878
+ "screenId": "himi_account_settings"
2879
2879
  }
2880
2880
  },
2881
2881
  "pressFeedback": "scale",
@@ -2957,95 +2957,6 @@ const SCREENS = runtimeSetting({
2957
2957
  "hiddenPath": "$service:himiStoreAccount.notMember"
2958
2958
  }
2959
2959
  },
2960
- {
2961
- "id": "himi_account.settings",
2962
- "body": {
2963
- "package": "himalaya",
2964
- "type": "HStack",
2965
- "props": {
2966
- "spacing": 12,
2967
- "children": [
2968
- {
2969
- "id": "",
2970
- "body": {
2971
- "package": "himalaya",
2972
- "type": "Icon",
2973
- "props": {
2974
- "name": "settings",
2975
- "size": 18,
2976
- "tint": "accentPrimary"
2977
- }
2978
- },
2979
- "modifiers": {
2980
- "accessibilityRole": "decorative"
2981
- }
2982
- },
2983
- {
2984
- "id": "",
2985
- "body": {
2986
- "package": "himalaya",
2987
- "type": "Text",
2988
- "props": {
2989
- "text": "My Account",
2990
- "style": "bodyEmphasis"
2991
- }
2992
- }
2993
- },
2994
- {
2995
- "id": "",
2996
- "body": {
2997
- "package": "himalaya",
2998
- "type": "Spacer",
2999
- "props": {}
3000
- }
3001
- },
3002
- {
3003
- "id": "",
3004
- "body": {
3005
- "package": "himalaya",
3006
- "type": "Icon",
3007
- "props": {
3008
- "name": "chevron_right",
3009
- "size": 16,
3010
- "tint": "textTertiary"
3011
- }
3012
- },
3013
- "modifiers": {
3014
- "accessibilityRole": "decorative"
3015
- }
3016
- }
3017
- ]
3018
- }
3019
- },
3020
- "modifiers": {
3021
- "background": {
3022
- "token": "surfaceElevated"
3023
- },
3024
- "border": {
3025
- "width": 1,
3026
- "color": {
3027
- "token": "border"
3028
- }
3029
- },
3030
- "cornerRadius": 8,
3031
- "padding": {
3032
- "leading": 14,
3033
- "trailing": 14,
3034
- "top": 13,
3035
- "bottom": 13
3036
- },
3037
- "onTap": {
3038
- "actionId": "himi.open",
3039
- "params": {
3040
- "screenId": "himi_account_settings"
3041
- }
3042
- },
3043
- "pressFeedback": "scale",
3044
- "haptic": "light",
3045
- "accessibilityLabel": "My Account",
3046
- "hiddenPath": "$service:himiStoreAccount.notMember"
3047
- }
3048
- },
3049
2960
  {
3050
2961
  "id": "",
3051
2962
  "body": {
@@ -9,7 +9,7 @@ import { generateMemberPhotoUploadUrl } from "@himalaya/wix-site-media";
9
9
  import { memberAccess } from "../_shared/member-access.js";
10
10
  import { memberAccountRoutes } from "../_shared/member-account-routes.js";
11
11
  import { copyParam, stashCopy } from "../_shared/himi-copy.js";
12
- import "./blocked-members.js";
12
+ import { svc as blockedMembers } from "./blocked-members.js";
13
13
 
14
14
  interface ProfileValues {
15
15
  displayName: string;
@@ -641,6 +641,9 @@ const svc = defineService<S, {
641
641
  const version = ++accountLoadVersion;
642
642
  photoUploadVersion += 1;
643
643
  stashCopy(arg);
644
+ // The blocked-members section also loads from its own nested onAppear on a device; starting it
645
+ // here too makes the root onAppear — the only one `himi test` fires — settle it. Re-entry-guarded.
646
+ void blockedMembers.load(arg).catch(() => undefined);
644
647
  try {
645
648
  const { email, scope, siteUrl, member } = await fetchMember((arg as { siteUrl?: unknown } | undefined)?.siteUrl);
646
649
  const current = await memberAccess();
@@ -3059,7 +3059,7 @@ const SCREENS = runtimeSetting({
3059
3059
  "onTap": {
3060
3060
  "actionId": "himi.open",
3061
3061
  "params": {
3062
- "screenId": "himi_view_profile"
3062
+ "screenId": "himi_account_settings"
3063
3063
  }
3064
3064
  },
3065
3065
  "pressFeedback": "scale",
@@ -3141,95 +3141,6 @@ const SCREENS = runtimeSetting({
3141
3141
  "hiddenPath": "$service:himiStoreAccount.notMember"
3142
3142
  }
3143
3143
  },
3144
- {
3145
- "id": "himi_account.settings",
3146
- "body": {
3147
- "package": "himalaya",
3148
- "type": "HStack",
3149
- "props": {
3150
- "spacing": 12,
3151
- "children": [
3152
- {
3153
- "id": "",
3154
- "body": {
3155
- "package": "himalaya",
3156
- "type": "Icon",
3157
- "props": {
3158
- "name": "settings",
3159
- "size": 18,
3160
- "tint": "accentPrimary"
3161
- }
3162
- },
3163
- "modifiers": {
3164
- "accessibilityRole": "decorative"
3165
- }
3166
- },
3167
- {
3168
- "id": "",
3169
- "body": {
3170
- "package": "himalaya",
3171
- "type": "Text",
3172
- "props": {
3173
- "text": "My Account",
3174
- "style": "bodyEmphasis"
3175
- }
3176
- }
3177
- },
3178
- {
3179
- "id": "",
3180
- "body": {
3181
- "package": "himalaya",
3182
- "type": "Spacer",
3183
- "props": {}
3184
- }
3185
- },
3186
- {
3187
- "id": "",
3188
- "body": {
3189
- "package": "himalaya",
3190
- "type": "Icon",
3191
- "props": {
3192
- "name": "chevron_right",
3193
- "size": 16,
3194
- "tint": "textTertiary"
3195
- }
3196
- },
3197
- "modifiers": {
3198
- "accessibilityRole": "decorative"
3199
- }
3200
- }
3201
- ]
3202
- }
3203
- },
3204
- "modifiers": {
3205
- "background": {
3206
- "token": "surfaceElevated"
3207
- },
3208
- "border": {
3209
- "width": 1,
3210
- "color": {
3211
- "token": "border"
3212
- }
3213
- },
3214
- "cornerRadius": 8,
3215
- "padding": {
3216
- "leading": 14,
3217
- "trailing": 14,
3218
- "top": 13,
3219
- "bottom": 13
3220
- },
3221
- "onTap": {
3222
- "actionId": "himi.open",
3223
- "params": {
3224
- "screenId": "himi_account_settings"
3225
- }
3226
- },
3227
- "pressFeedback": "scale",
3228
- "haptic": "light",
3229
- "accessibilityLabel": "My Account",
3230
- "hiddenPath": "$service:himiStoreAccount.notMember"
3231
- }
3232
- },
3233
3144
  {
3234
3145
  "id": "",
3235
3146
  "body": {
@@ -9,7 +9,7 @@ import { generateMemberPhotoUploadUrl } from "@himalaya/wix-site-media";
9
9
  import { memberAccess } from "../_shared/member-access.js";
10
10
  import { memberAccountRoutes } from "../_shared/member-account-routes.js";
11
11
  import { copyParam, stashCopy } from "../_shared/himi-copy.js";
12
- import "./blocked-members.js";
12
+ import { svc as blockedMembers } from "./blocked-members.js";
13
13
 
14
14
  interface ProfileValues {
15
15
  displayName: string;
@@ -641,6 +641,9 @@ const svc = defineService<S, {
641
641
  const version = ++accountLoadVersion;
642
642
  photoUploadVersion += 1;
643
643
  stashCopy(arg);
644
+ // The blocked-members section also loads from its own nested onAppear on a device; starting it
645
+ // here too makes the root onAppear — the only one `himi test` fires — settle it. Re-entry-guarded.
646
+ void blockedMembers.load(arg).catch(() => undefined);
644
647
  try {
645
648
  const { email, scope, siteUrl, member } = await fetchMember((arg as { siteUrl?: unknown } | undefined)?.siteUrl);
646
649
  const current = await memberAccess();