@wix/himalaya-cli 0.1576.0 → 0.1577.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 (76) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/index.d.ts +64 -6
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/online-programs/src/index.d.ts +87 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +15 -3
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-online-programs.mjs +42 -0
  5. package/dist/cli.mjs +10810 -10592
  6. package/dist/preview-assets.generated.bin +0 -0
  7. package/fixtures/wix-canned.json +56 -3
  8. package/guides/one-app-section-mappings.md +1 -1
  9. package/guides/one-app-to-himi-app.md +50 -1
  10. package/guides/sdk-reference.json +133 -9
  11. package/package.json +2 -2
  12. package/templates/beauty-salon/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  13. package/templates/beauty-salon/tier5-src/_shared/owner-load-error.ts +8 -0
  14. package/templates/beauty-salon-owner/dev/index.ts +52 -27
  15. package/templates/beauty-salon-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  16. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  17. package/templates/branded-lite/config.ts +7 -0
  18. package/templates/branded-lite/dev/index.ts +833 -0
  19. package/templates/branded-lite/himalaya.content.json +3 -0
  20. package/templates/branded-lite/l10n/en.json +4 -2
  21. package/templates/branded-lite/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  22. package/templates/branded-lite/tier5-src/_shared/owner-load-error.ts +8 -0
  23. package/templates/branded-lite/tier5-src/himi-branded-lite-member-programs/index.ts +658 -0
  24. package/templates/community-club/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  25. package/templates/community-club/tier5-src/_shared/owner-load-error.ts +8 -0
  26. package/templates/community-club-owner/dev/index.ts +52 -27
  27. package/templates/community-club-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  28. package/templates/community-club-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  29. package/templates/events-meetups/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  30. package/templates/events-meetups/tier5-src/_shared/owner-load-error.ts +8 -0
  31. package/templates/events-meetups-owner/dev/index.ts +52 -27
  32. package/templates/events-meetups-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  33. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  34. package/templates/gym-fitness/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  35. package/templates/gym-fitness/tier5-src/_shared/owner-load-error.ts +8 -0
  36. package/templates/gym-fitness-owner/dev/index.ts +52 -27
  37. package/templates/gym-fitness-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  38. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  39. package/templates/himi-chat/tier5-src/_shared/owner-load-error.ts +8 -0
  40. package/templates/nonprofit-cause/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  41. package/templates/nonprofit-cause/tier5-src/_shared/owner-load-error.ts +8 -0
  42. package/templates/nonprofit-cause-owner/dev/index.ts +52 -27
  43. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  44. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  45. package/templates/owner-lite/dev/index.ts +52 -27
  46. package/templates/owner-lite/tier5-src/_shared/owner-load-error.ts +8 -0
  47. package/templates/owner-lite/tier5-src/himi-owner-lite-post/index.ts +20 -8
  48. package/templates/podcast-creator/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  49. package/templates/podcast-creator/tier5-src/_shared/owner-load-error.ts +8 -0
  50. package/templates/podcast-creator-owner/dev/index.ts +52 -27
  51. package/templates/podcast-creator-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  52. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  53. package/templates/portfolio-creative/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  54. package/templates/portfolio-creative/tier5-src/_shared/owner-load-error.ts +8 -0
  55. package/templates/portfolio-creative-owner/dev/index.ts +52 -27
  56. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  57. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  58. package/templates/restaurant/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  59. package/templates/restaurant/tier5-src/_shared/owner-load-error.ts +8 -0
  60. package/templates/restaurant-owner/dev/index.ts +52 -27
  61. package/templates/restaurant-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  62. package/templates/restaurant-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  63. package/templates/retail-store/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  64. package/templates/retail-store/tier5-src/_shared/owner-load-error.ts +8 -0
  65. package/templates/retail-store-owner/dev/index.ts +52 -27
  66. package/templates/retail-store-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  67. package/templates/retail-store-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  68. package/templates/yoga-studio/config.ts +7 -0
  69. package/templates/yoga-studio/dev/index.ts +833 -0
  70. package/templates/yoga-studio/himalaya.content.json +3 -0
  71. package/templates/yoga-studio/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  72. package/templates/yoga-studio/tier5-src/_shared/owner-load-error.ts +8 -0
  73. package/templates/yoga-studio/tier5-src/himi-branded-lite-member-programs/index.ts +658 -0
  74. package/templates/yoga-studio-owner/dev/index.ts +52 -27
  75. package/templates/yoga-studio-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  76. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
Binary file
@@ -528,6 +528,59 @@
528
528
  "total": 0
529
529
  }
530
530
  },
531
+ "POST /online-programs/v3/participants/query": {
532
+ "participants": [
533
+ {
534
+ "id": "part-0001",
535
+ "programId": "prog-0001",
536
+ "memberId": "mem-0001",
537
+ "enrollmentStatus": "JOINED",
538
+ "progressStatus": "IN_PROGRESS",
539
+ "createdDate": "2026-10-01T09:00:00.000Z",
540
+ "progress": {
541
+ "totalStepsCompleted": 12,
542
+ "totalStepsAvailable": 30,
543
+ "completionPercentage": 40
544
+ }
545
+ }
546
+ ],
547
+ "pagingMetadata": {
548
+ "count": 1,
549
+ "cursors": {
550
+ "next": null
551
+ }
552
+ }
553
+ },
554
+ "POST /online-programs/v3/participants/stats": {
555
+ "participationStats": [
556
+ {
557
+ "programId": "prog-0001",
558
+ "participantsCount": 18
559
+ },
560
+ {
561
+ "programId": "prog-0002",
562
+ "participantsCount": 7
563
+ }
564
+ ]
565
+ },
566
+ "GET /_api/program-categories-service/v3/categories": {
567
+ "categories": [
568
+ {
569
+ "id": "cat-0001",
570
+ "label": "Brewing",
571
+ "assignedTo": [
572
+ "prog-0001"
573
+ ]
574
+ },
575
+ {
576
+ "id": "cat-0002",
577
+ "label": "Roasting",
578
+ "assignedTo": [
579
+ "prog-0002"
580
+ ]
581
+ }
582
+ ]
583
+ },
531
584
  "POST /online-programs/v3/programs/query": {
532
585
  "programs": [
533
586
  {
@@ -954,17 +1007,17 @@
954
1007
  "total": 2
955
1008
  }
956
1009
  },
957
- "GET /loyalty/v1/program": {
1010
+ "GET /loyalty-programs/v1/program": {
958
1011
  "loyaltyProgram": {
959
1012
  "name": "Roastery Rewards",
960
1013
  "status": "ACTIVE",
961
1014
  "pointDefinition": {
962
1015
  "customName": "beans",
963
- "icon": "STAR"
1016
+ "icon": { "url": "fixture-star.svg" }
964
1017
  }
965
1018
  }
966
1019
  },
967
- "GET /loyalty/v1/rewards": {
1020
+ "GET /loyalty-rewards/v1/rewards": {
968
1021
  "rewards": [
969
1022
  {
970
1023
  "id": "rw-0001",
@@ -47,7 +47,7 @@ The **Himalaya implementation** cell is blank for every unassigned row. Notes on
47
47
 
48
48
  | Source sectionDefinitionId | Source viewer component | Himalaya implementation | Placement / reuse | Class | Settings, actions and gaps |
49
49
  | --- | --- | --- | --- | --- | --- |
50
- | `achievements_list_section` | `wix-one-app-achievements.SectionMemberChallengesScreen` | [Programs list/detail](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/apps/himi-branded-lite/dev/index.ts) + [programs worker](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-programs/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; adaptation needed | Partial | Reuse Online Programs catalog/enrolment logic; the program-detail worker explicitly identifies the legacy CHALLENGES app ID. Translate the section selection and source extraProps.limit=2; inline composition is still required. |
50
+ | `achievements_list_section` | `wix-one-app-achievements.SectionMemberChallengesScreen` | [Programs list/detail](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/apps/himi-branded-lite/dev/index.ts) + [programs worker](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-programs/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; member list added | Partial | `himi_member_programs` (worker `himi-branded-lite-member-programs`) is the member list: each card carries the signed-in member's standing from Participants v3 / Join Applications v3 (Joined, Program complete, Program ended, Pending request, Request approved, Invited, Participation suspended), a progress bar once started, the price before joining, the "All programs / Programs I joined" and category filters, cursor paging and pull-to-refresh; an ended program the member never joined is dropped. Still open: the 2-card section mode with "See all" (`extraProps.limit=2`, inline composition), join / cancel-request actions on the card itself (the card opens the program, which owns them), and Pricing Plans benefits ("Included in your plan"). |
51
51
  | `achievements_carousel_section` | `wix-one-app-achievements.MemberChallengesCarousel` | [Programs data/detail](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-programs/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") + [Core Carousel](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/src/builder.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; adaptation needed | Partial | Reuse the Programs feature and compose a carousel; preserve source extraProps.limit=5 and selected programs. No ready-made legacy Challenges carousel adapter is claimed. |
52
52
  | `achievements_participant_carousel_section` | `wix-one-app-achievements.ParticipantChallengesCarousel` | | | Empty | The public Programs catalog is not a member-participating-programs carousel. No verified consumer participant/progress list implementation was found. |
53
53
 
@@ -255,7 +255,10 @@ Apply these interpretation rules:
255
255
  bar that cannot be inspected is reported as unverified. The maintained `inviteAction`
256
256
  builder is recognized; its conditional ID and hidden binding must also appear in
257
257
  `topBarDefault.actions` with a configured `navLogicBundle`, even when the screen
258
- overrides its bar. A screen-only binding is not subscribed. Platform definitions establish
258
+ overrides its bar. Observer/listener badges require live count bindings with
259
+ matching action IDs/value paths in the nav default and an accessible label.
260
+ Static counts cannot stand in for unavailable source data. A screen-only
261
+ binding is not subscribed. Platform definitions establish
259
262
  a feature to account for; they do not alone prove visibility or access for every
260
263
  visitor or member. Resolve those rules separately. This check is specific to this
261
264
  migration workflow; it does not change the behavior of `himi validate`.
@@ -446,6 +449,52 @@ Apply these interpretation rules:
446
449
  shared. No invitation is created while migrating or just loading the screen.
447
450
  Source Invite produces an `interaction` coverage row requiring behavioral proof;
448
451
  unresolved transport or permissions remain gaps, never silent omission.
452
+ - **Preserve source badge behavior.** Collected button definitions retain
453
+ `badgeObserverId`, `badgeListenerId` and `showBadgeOnVisitorMode`. Keep the
454
+ counter's actual site/member/shopper scope and visitor policy; the source's
455
+ ordinary observer/listener button defaults to member-only observation when the
456
+ visitor flag is absent. Coverage inventories these counters as separate
457
+ behavioral obligations for raw, iOS and Android definitions. It also inventories
458
+ custom-component behavior: a custom component can own a counter internally,
459
+ without observer/listener fields. Do not infer a count badge for every custom
460
+ component. Inspect its implementation and retain unknown behavior as unresolved.
461
+
462
+ Use a live `badge: { kind: "count", valuePath: "$service:sourceBadges.count" }`
463
+ only after implementing the actual source counter. Preserve the source button
464
+ ID, or map its current `top-bar` coverage row to the target `screenId` and
465
+ `controlId` when renaming it. A sibling action's badge cannot satisfy that row;
466
+ changed source definitions invalidate the mapping. Declare the same action ID
467
+ and value path in `navigation.topBarDefault.actions` and any complete screen
468
+ override, with `navLogicBundle`. Action IDs must be unique in each bar; distinct
469
+ source counters need distinct target actions within each source platform. Both
470
+ actions need their own tap handler and accessible label. Do not supply a static
471
+ `value` as a fallback. The top-bar check establishes inspectable wiring, not
472
+ the counter's data source, availability, refresh, permission or accessibility
473
+ behavior. A configured worker URL alone proves none of those.
474
+
475
+ Keep a successful zero as `0` and unavailable as `null`; verify positive, zero,
476
+ failed/missing reads and source/site/account replacement, including a delayed
477
+ response from the previous identity. Verify badge visibility and screen-reader
478
+ output against the source. A persistent nav worker needs a supported refresh
479
+ path; a screen-only load, page-row count or foreground push receipt count is
480
+ insufficient. The source Member notification aggregate is MOBILE/UNSEEN, capped
481
+ at100. `countUnseenNotifications({ site: boundMetaSiteId })` reads that aggregate
482
+ through the source Member route. It requires the updated native core, rebuilt
483
+ consuming binaries and published SDK; default web and old binaries remain
484
+ unavailable for this reader. Never replace that refusal with zero.
485
+ Chat counts unread rooms, while legacy cart counters can include unsynced local
486
+ quantities; a different shopper's or headless cart's zero is not a substitute.
487
+ If the source reader/refresh path is unverified, leave that badge unresolved.
488
+ Changing a button definition or its visitor policy invalidates its previous
489
+ coverage mapping and requires new behavioral evidence. `coverage sync` replaces
490
+ changed or moved header rows for the same source button within its bar with
491
+ unmapped rows. A one-to-one change between an observer/listener badge and a
492
+ custom component is a replacement. A different button at an old index, or a
493
+ remaining custom behavior after its explicit badge is removed, cannot hide a
494
+ removal. Older ledger rows without stable `sourceButtonId` metadata require
495
+ explicit reconciliation when changed; syncing unchanged evidence adds that
496
+ metadata. Removing a button or behavior without a replacement still requires
497
+ explicit ledger reconciliation.
449
498
  - Verify the migrated app's native top bar, bottom tabs, back navigation and
450
499
  configured actions on the affected devices, including RTL. A web screenshot
451
500
  alone does not prove native navigation or control availability. Record any
@@ -22898,44 +22898,70 @@
22898
22898
  "jsdoc": "/** The per-call header map for `opts`, or undefined when there is nothing to add — so\n * the no-options path calls the bridge with exactly the 3 arguments it always did. */",
22899
22899
  "decl": "export function wixCall<T>(method: string, path: string, body?: unknown, readOptions?: WixCallOptions): Promise<T>;"
22900
22900
  },
22901
+ {
22902
+ "name": "WixLoyaltyImage",
22903
+ "kind": "interface",
22904
+ "jsdoc": "",
22905
+ "decl": "export interface WixLoyaltyImage {\n id?: string;\n url?: string;\n height?: number;\n width?: number;\n altText?: string;\n filename?: string;\n}"
22906
+ },
22907
+ {
22908
+ "name": "WixLoyaltyRewardConfig",
22909
+ "kind": "interface",
22910
+ "jsdoc": "",
22911
+ "decl": "export interface WixLoyaltyRewardConfig {\n tierId?: string;\n costInPoints?: number;\n amount?: number;\n percentage?: number;\n}"
22912
+ },
22901
22913
  {
22902
22914
  "name": "WixLoyaltyProgram",
22903
22915
  "kind": "interface",
22904
22916
  "jsdoc": "",
22905
- "decl": "export interface WixLoyaltyProgram {\n id?: string;\n name?: string;\n /** ACTIVE | DRAFT | PAUSED */\n status?: string;\n pointDefinition?: { customName?: string; icon?: string };\n}"
22917
+ "decl": "export interface WixLoyaltyProgram {\n id?: string;\n name?: string;\n /** ACTIVE | DRAFT | PAUSED */\n status?: string;\n pointDefinition?: { customName?: string; icon?: WixLoyaltyImage };\n}"
22906
22918
  },
22907
22919
  {
22908
22920
  "name": "WixLoyaltyReward",
22909
22921
  "kind": "interface",
22910
22922
  "jsdoc": "",
22911
- "decl": "export interface WixLoyaltyReward {\n id: string;\n name?: string;\n type?: string;\n requiredPoints?: number;\n active?: boolean;\n}"
22923
+ "decl": "export interface WixLoyaltyReward {\n id: string;\n name?: string;\n type?: string;\n /** Legacy adapter field. REST costs live in the reward's tier configurations. */\n requiredPoints?: number;\n discountAmount?: { configsByTier?: { tierId?: string; costInPoints?: number; amount?: string }[] };\n couponReward?: {\n fixedAmount?: { configsByTier?: WixLoyaltyRewardConfig[] };\n percentage?: { configsByTier?: WixLoyaltyRewardConfig[] };\n freeShipping?: { configsByTier?: WixLoyaltyRewardConfig[] };\n };\n active?: boolean;\n}"
22912
22924
  },
22913
22925
  {
22914
22926
  "name": "WixLoyaltyTier",
22915
22927
  "kind": "interface",
22916
22928
  "jsdoc": "",
22917
- "decl": "export interface WixLoyaltyTier {\n /** REST returns `id` (proto `_id`). */\n id?: string;\n tierDefinition?: { name?: string; icon?: string };\n requiredPoints?: number;\n}"
22929
+ "decl": "export interface WixLoyaltyTier {\n /** REST returns `id` (proto `_id`). */\n id?: string;\n tierDefinition?: { name?: string; icon?: WixLoyaltyImage };\n requiredPoints?: number;\n}"
22930
+ },
22931
+ {
22932
+ "name": "WixLoyaltyEarningRule",
22933
+ "kind": "interface",
22934
+ "jsdoc": "",
22935
+ "decl": "export interface WixLoyaltyEarningRule {\n id?: string;\n title?: string;\n status?: string;\n triggerActivityType?: string;\n fixedAmount?: { configs?: { tierId?: string; points?: number }[] };\n conversionRate?: { field?: string; configs?: { tierId?: string; moneyAmount?: number; points?: number }[] };\n}"
22918
22936
  },
22919
22937
  {
22920
22938
  "name": "getLoyaltyProgram",
22921
22939
  "kind": "function",
22922
- "jsdoc": "/** GET /loyalty/v1/program → { loyaltyProgram }. */",
22940
+ "jsdoc": "/** GET /loyalty-programs/v1/program → { loyaltyProgram }. */",
22923
22941
  "decl": "export function getLoyaltyProgram(readOptions?: WixCallOptions): Promise<{ loyaltyProgram?: WixLoyaltyProgram; program?: WixLoyaltyProgram }>;",
22924
- "http": "GET /loyalty/v1/program"
22942
+ "http": "GET /loyalty-programs/v1/program"
22925
22943
  },
22926
22944
  {
22927
22945
  "name": "listLoyaltyRewards",
22928
22946
  "kind": "function",
22929
- "jsdoc": "/** GET /loyalty/v1/rewards → { rewards }. */",
22947
+ "jsdoc": "/** GET /loyalty-rewards/v1/rewards → { rewards }. */",
22930
22948
  "decl": "export function listLoyaltyRewards(readOptions?: WixCallOptions): Promise<{ rewards?: WixLoyaltyReward[] }>;",
22931
- "http": "GET /loyalty/v1/rewards"
22949
+ "http": "GET /loyalty-rewards/v1/rewards"
22932
22950
  },
22933
22951
  {
22934
22952
  "name": "listLoyaltyTiers",
22935
22953
  "kind": "function",
22936
- "jsdoc": "/** GET /loyalty/v1/tiers → { tiers }. The PUBLIC program tier ladder\n * (wix.loyalty.v1.tier) — NOT the private per-customer tiers-program dashboard. */",
22954
+ "jsdoc": "/** GET /loyalty-tiers/v1/tiers → { tiers }. The program tier ladder. */",
22937
22955
  "decl": "export function listLoyaltyTiers(readOptions?: WixCallOptions): Promise<{ tiers?: WixLoyaltyTier[] }>;",
22938
- "http": "GET /loyalty/v1/tiers"
22956
+ "http": "GET /loyalty-tiers/v1/tiers"
22957
+ },
22958
+ {
22959
+ "name": "listLoyaltyEarningRules",
22960
+ "kind": "function",
22961
+ "jsdoc": "/** Active and inactive earning rules in their raw REST shape; callers choose visibility.\n * @scope visitor\n */",
22962
+ "decl": "export function listLoyaltyEarningRules(readOptions?: WixCallOptions): Promise<{ earningRules?: WixLoyaltyEarningRule[] }>;",
22963
+ "http": "GET /_api/loyalty-earning-rules/v1/earning-rules/rules",
22964
+ "scope": "visitor"
22939
22965
  },
22940
22966
  {
22941
22967
  "name": "LoyaltyOverview",
@@ -24094,6 +24120,104 @@
24094
24120
  "kind": "function",
24095
24121
  "jsdoc": "/** The cashier handle to settle, or \"\" when no payable order is available. */",
24096
24122
  "decl": "export function payableIdOf(participant?: WixJoinedParticipant): string;"
24123
+ },
24124
+ {
24125
+ "name": "MEMBER_ENROLLMENT_STATUSES",
24126
+ "kind": "const",
24127
+ "jsdoc": "/** `Participant.enrollmentStatus` values the member list filters on. */",
24128
+ "decl": "export const MEMBER_ENROLLMENT_STATUSES = {\n joined: \"JOINED\",\n suspended: \"SUSPENDED\",\n unknown: \"UNKNOWN_ENROLLMENT_STATUS\",\n} as const;"
24129
+ },
24130
+ {
24131
+ "name": "MEMBER_FINISHED_PROGRESS_STATUSES",
24132
+ "kind": "const",
24133
+ "jsdoc": "/** `Participant.progressStatus` values that still count as a membership once the enrollment is over. */",
24134
+ "decl": "export const MEMBER_FINISHED_PROGRESS_STATUSES = [\"COMPLETED\", \"FAILED\"] as const;"
24135
+ },
24136
+ {
24137
+ "name": "WixMemberParticipantsQuery",
24138
+ "kind": "interface",
24139
+ "jsdoc": "",
24140
+ "decl": "export interface WixMemberParticipantsQuery {\n /** The signed-in member's id (`getMyMember().member.id`). Required: without it the query is the roster of everyone. */\n memberId: string;\n /** The `pagingMetadata.cursors.next` of the previous page; omit for the first page. */\n cursor?: string;\n /** Page size, default 100 (the upstream page cap for this query). */\n limit?: number;\n}"
24141
+ },
24142
+ {
24143
+ "name": "WixQueryMemberParticipantsResponse",
24144
+ "kind": "interface",
24145
+ "jsdoc": "",
24146
+ "decl": "export interface WixQueryMemberParticipantsResponse extends WixQueryParticipantsResponse {\n pagingMetadata?: WixQueryParticipantsResponse[\"pagingMetadata\"] & { cursors?: { next?: string | null } };\n}"
24147
+ },
24148
+ {
24149
+ "name": "queryMemberParticipants",
24150
+ "kind": "function",
24151
+ "jsdoc": "/**\n * POST /online-programs/v3/participants/query — the MEMBER'S participations, cursor-paged, with\n * progress. Joined and suspended enrollments, plus completed/failed ones whose enrollment has\n * ended, so a finished program still shows its outcome; left, removed and auto-removed\n * memberships are excluded. The query language has no `programId: {$in}` on this\n * endpoint, so callers match memberships to displayed programs locally.\n *\n * @scope member — requires the signed-in site member; `memberId` must be that member's own id\n * (`getMyMember().member.id`). An empty `participants` list means the member has no such\n * membership, never that the read failed: a failure rejects.\n */",
24152
+ "decl": "export function queryMemberParticipants(opts: WixMemberParticipantsQuery): Promise<WixQueryMemberParticipantsResponse>;",
24153
+ "http": "POST /online-programs/v3/participants/query",
24154
+ "scope": "member"
24155
+ },
24156
+ {
24157
+ "name": "WixProgramParticipationStats",
24158
+ "kind": "interface",
24159
+ "jsdoc": "",
24160
+ "decl": "export interface WixProgramParticipationStats {\n programId?: string;\n participantsCount?: number;\n autoRemovedCount?: number;\n}"
24161
+ },
24162
+ {
24163
+ "name": "WixGetParticipationStatsResponse",
24164
+ "kind": "interface",
24165
+ "jsdoc": "",
24166
+ "decl": "export interface WixGetParticipationStatsResponse { participationStats?: WixProgramParticipationStats[] }"
24167
+ },
24168
+ {
24169
+ "name": "getParticipationStats",
24170
+ "kind": "function",
24171
+ "jsdoc": "/** POST /online-programs/v3/participants/stats — participant counts for a batch of programs (one call per page).\n * `programIds` must be non-empty (an empty batch returns `{ participationStats: [] }` without a call);\n * a program missing from the answer has no count, not zero.\n * @scope visitor — counts are public; an anonymous visitor session is enough. */",
24172
+ "decl": "export function getParticipationStats(programIds: string[]): Promise<WixGetParticipationStatsResponse>;",
24173
+ "http": "POST /online-programs/v3/participants/stats",
24174
+ "scope": "visitor"
24175
+ },
24176
+ {
24177
+ "name": "WixJoinApplicationStatus",
24178
+ "kind": "type",
24179
+ "jsdoc": "/** `JoinApplication.status` — the member's standing BEFORE a participant exists (a private or paid program). */",
24180
+ "decl": "export type WixJoinApplicationStatus =\n | \"INVITED\"\n | \"APPROVAL_PENDING\"\n | \"APPROVED\"\n | \"PAYMENT_PENDING\"\n | \"SUSPENDED\"\n | \"DECLINED\"\n | \"CANCELLED\"\n | string;"
24181
+ },
24182
+ {
24183
+ "name": "WixJoinApplication",
24184
+ "kind": "interface",
24185
+ "jsdoc": "",
24186
+ "decl": "export interface WixJoinApplication {\n id?: string;\n programId?: string;\n memberId?: string;\n status?: WixJoinApplicationStatus;\n paymentStatus?: string;\n /** Set once the application became a participant. */\n participantId?: string;\n createdDate?: string;\n updatedDate?: string;\n}"
24187
+ },
24188
+ {
24189
+ "name": "WixGetCurrentJoinApplicationResponse",
24190
+ "kind": "interface",
24191
+ "jsdoc": "",
24192
+ "decl": "export interface WixGetCurrentJoinApplicationResponse { joinApplication?: WixJoinApplication }"
24193
+ },
24194
+ {
24195
+ "name": "getCurrentJoinApplication",
24196
+ "kind": "function",
24197
+ "jsdoc": "/** GET /online-programs/participants/v3/join-applications/current/{programId} — the signed-in member's\n * own application to ONE program, or none. Used per card only where an application can exist\n * (a private or a priced program the member has not joined). An answer with no `joinApplication`\n * means the member never applied.\n * @scope member — requires the signed-in site member; a visitor session has no application to read. */",
24198
+ "decl": "export function getCurrentJoinApplication(programId: string): Promise<WixGetCurrentJoinApplicationResponse>;",
24199
+ "http": "GET /online-programs/participants/v3/join-applications/current/{…}",
24200
+ "scope": "member"
24201
+ },
24202
+ {
24203
+ "name": "WixProgramCategory",
24204
+ "kind": "interface",
24205
+ "jsdoc": "",
24206
+ "decl": "export interface WixProgramCategory {\n id?: string;\n label?: string;\n /** Program ids the category is assigned to. */\n assignedTo?: string[];\n}"
24207
+ },
24208
+ {
24209
+ "name": "WixListProgramCategoriesResponse",
24210
+ "kind": "interface",
24211
+ "jsdoc": "",
24212
+ "decl": "export interface WixListProgramCategoriesResponse { categories?: WixProgramCategory[] }"
24213
+ },
24214
+ {
24215
+ "name": "listProgramCategories",
24216
+ "kind": "function",
24217
+ "jsdoc": "/** GET /_api/program-categories-service/v3/categories — every program category of the site (the\n * category filter's options). `/_api/…` paths ride the same bridge as the public ones (forms,\n * bookings-v2 and ecom already do). An empty `categories` list means the site has none.\n * @scope member — the One App member programs list calls it with the member's identity. NOT verified\n * live here: codegen/wix/auto/lock.json lists only the APP identity (ONLINE_PROGRAMS.CATEGORY_READ), so a\n * visitor or member token can get 403. A caller must treat a rejection as \"no category filter\", never\n * as an error screen. */",
24218
+ "decl": "export function listProgramCategories(): Promise<WixListProgramCategoriesResponse>;",
24219
+ "http": "GET /_api/program-categories-service/v3/categories",
24220
+ "scope": "member"
24097
24221
  }
24098
24222
  ]
24099
24223
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1576.0",
3
+ "version": "0.1577.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": "b3770b71ba8570708ab97e43a149a8ee2880f9fea27a618d80902862"
74
+ "falconPackageHash": "9902ef55d169da2c82868b986ceafb0c54b8102e501f513b72e4c8c0"
75
75
  }
@@ -119,6 +119,7 @@ export const HOSTED_SCREEN_VERTICALS: Readonly<Record<string, readonly BrandedLi
119
119
  himi_portfolio: ["portfolio"],
120
120
  himi_portfolio_project: ["portfolio"],
121
121
  himi_programs: ["programs"],
122
+ himi_member_programs: ["programs"],
122
123
  himi_reservations: ["reservations"],
123
124
  himi_reserve: ["restaurants"],
124
125
  himi_review: ["reviews"],
@@ -194,6 +194,14 @@ export function isTransportFailure(e: unknown): boolean {
194
194
  return TRANSPORT.some((re) => re.test(msg));
195
195
  }
196
196
 
197
+ /** A failed READ says nothing about the record's existence when Wix is
198
+ * unreachable, overloaded or failing. Unlike the legacy bridge predicate this
199
+ * is independent of preview mode; a live preview's gateway failure is one too. */
200
+ export function readWasUnreachable(e: unknown): boolean {
201
+ const msg = String((e as Error)?.message ?? e ?? "");
202
+ return isTransportFailure(e) || /HTTP (?:408|429|5\d{2})\b/.test(msg);
203
+ }
204
+
197
205
  /** Transport failures that happen while CONNECTING — no connection, no route, no such host,
198
206
  * connection refused — so the request provably never left the device. Every other
199
207
  * transport failure (a timeout, a reset, a bad or truncated response, a browser's fetch
@@ -65684,16 +65684,17 @@ const SCREENS = runtimeSetting({
65684
65684
  "type": "VStack",
65685
65685
  "props": {
65686
65686
  "spacing": 10,
65687
+ "alignment": "leading",
65687
65688
  "children": [
65688
65689
  {
65689
- "id": "himi_owner_lite_inbox_thread.sk1",
65690
+ "id": "himi_owner_lite_inbox_thread.loading_text",
65690
65691
  "body": {
65691
65692
  "package": "himalaya",
65692
- "type": "Skeleton",
65693
+ "type": "Text",
65693
65694
  "props": {
65694
- "width": 220,
65695
- "height": 44,
65696
- "cornerRadius": 16
65695
+ "text": "Loading conversation…",
65696
+ "style": "body",
65697
+ "color": "textSecondary"
65697
65698
  }
65698
65699
  }
65699
65700
  },
@@ -65701,51 +65702,75 @@ const SCREENS = runtimeSetting({
65701
65702
  "id": "",
65702
65703
  "body": {
65703
65704
  "package": "himalaya",
65704
- "type": "HStack",
65705
+ "type": "VStack",
65705
65706
  "props": {
65707
+ "spacing": 10,
65706
65708
  "children": [
65709
+ {
65710
+ "id": "himi_owner_lite_inbox_thread.sk1",
65711
+ "body": {
65712
+ "package": "himalaya",
65713
+ "type": "Skeleton",
65714
+ "props": {
65715
+ "width": 220,
65716
+ "height": 44,
65717
+ "cornerRadius": 16
65718
+ }
65719
+ }
65720
+ },
65707
65721
  {
65708
65722
  "id": "",
65709
65723
  "body": {
65710
65724
  "package": "himalaya",
65711
- "type": "Spacer",
65712
- "props": {}
65725
+ "type": "HStack",
65726
+ "props": {
65727
+ "children": [
65728
+ {
65729
+ "id": "",
65730
+ "body": {
65731
+ "package": "himalaya",
65732
+ "type": "Spacer",
65733
+ "props": {}
65734
+ }
65735
+ },
65736
+ {
65737
+ "id": "himi_owner_lite_inbox_thread.sk2",
65738
+ "body": {
65739
+ "package": "himalaya",
65740
+ "type": "Skeleton",
65741
+ "props": {
65742
+ "width": 180,
65743
+ "height": 44,
65744
+ "cornerRadius": 16
65745
+ }
65746
+ }
65747
+ }
65748
+ ]
65749
+ }
65713
65750
  }
65714
65751
  },
65715
65752
  {
65716
- "id": "himi_owner_lite_inbox_thread.sk2",
65753
+ "id": "himi_owner_lite_inbox_thread.sk3",
65717
65754
  "body": {
65718
65755
  "package": "himalaya",
65719
65756
  "type": "Skeleton",
65720
65757
  "props": {
65721
- "width": 180,
65722
- "height": 44,
65758
+ "width": 240,
65759
+ "height": 64,
65723
65760
  "cornerRadius": 16
65724
65761
  }
65725
65762
  }
65726
65763
  }
65727
65764
  ]
65728
65765
  }
65729
- }
65730
- },
65731
- {
65732
- "id": "himi_owner_lite_inbox_thread.sk3",
65733
- "body": {
65734
- "package": "himalaya",
65735
- "type": "Skeleton",
65736
- "props": {
65737
- "width": 240,
65738
- "height": 64,
65739
- "cornerRadius": 16
65740
- }
65766
+ },
65767
+ "modifiers": {
65768
+ "fillMaxWidth": true,
65769
+ "accessibilityRole": "decorative"
65741
65770
  }
65742
65771
  }
65743
65772
  ]
65744
65773
  }
65745
- },
65746
- "modifiers": {
65747
- "fillMaxWidth": true,
65748
- "accessibilityRole": "decorative"
65749
65774
  }
65750
65775
  }
65751
65776
  },
@@ -194,6 +194,14 @@ export function isTransportFailure(e: unknown): boolean {
194
194
  return TRANSPORT.some((re) => re.test(msg));
195
195
  }
196
196
 
197
+ /** A failed READ says nothing about the record's existence when Wix is
198
+ * unreachable, overloaded or failing. Unlike the legacy bridge predicate this
199
+ * is independent of preview mode; a live preview's gateway failure is one too. */
200
+ export function readWasUnreachable(e: unknown): boolean {
201
+ const msg = String((e as Error)?.message ?? e ?? "");
202
+ return isTransportFailure(e) || /HTTP (?:408|429|5\d{2})\b/.test(msg);
203
+ }
204
+
197
205
  /** Transport failures that happen while CONNECTING — no connection, no route, no such host,
198
206
  * connection refused — so the request provably never left the device. Every other
199
207
  * transport failure (a timeout, a reset, a bad or truncated response, a browser's fetch
@@ -10,7 +10,7 @@ import { getPost, getDraftPost, publishDraftPost, revertDraftPost, deleteDraftPo
10
10
  import { parseRicosJson } from "@himalaya/wix-rich-content";
11
11
  import { openRichLink } from "../_shared/rich-content-link.js";
12
12
  import { richBody } from "../_shared/rich-body.js";
13
- import { ownerLoadError, isBridgeUnavailable, isTransportFailure, isOwnerPreviewDemo, ownerDemoFallback, ownerWriteError, isNotFound } from "../_shared/owner-load-error.js";
13
+ import { ownerLoadError, isBridgeUnavailable, readWasUnreachable, isOwnerPreviewDemo, ownerDemoFallback, ownerWriteError, isNotFound } from "../_shared/owner-load-error.js";
14
14
  import { DEMO_POSTS, DEMO_NOTE, DEMO_SAVE_NOTE } from "../_shared/owner-preview-demo.js";
15
15
  import { stashCopy, copyParam } from "../_shared/himi-copy.js";
16
16
  import { get as dbGet, upsert as dbUpsert, remove as dbRemove, type DbEntity } from "../_shared/owner-local-db.js";
@@ -270,14 +270,24 @@ async function refresh(prev: PostState, id: string, actionMessage = "", opts: {
270
270
  try { post = (await getPost(id)).post; } catch (e) { lastError = postError = e; /* draft-only */ }
271
271
  try { draft = (await getDraftPost(id)).draftPost; } catch (e) { lastError = e; /* published-only or missing */ }
272
272
  if (!post && !draft) {
273
- // Both arms swallowed their errors above; surface the DESIGNED bridge
274
- // boundary (and a device with no connection) so the callers' catches can fall
275
- // back to the cached row or the demo post — never "post not found" for a post
276
- // that was only unreachable.
273
+ // Both arms swallowed their errors above. Neither a failed published read
274
+ // nor a missing draft proves the post is gone.
277
275
  // Either read counts: a published-only post's draft read is always a 404, so the
278
276
  // published read's failure is the one that says whether the post was only unreachable.
279
277
  for (const err of [postError, lastError]) {
280
- if (isBridgeUnavailable(err) || isTransportFailure(err)) throw err;
278
+ // getPost may wrap the original read failure when its query fallback is
279
+ // empty. Preserve that cause's status instead of painting the wrapper's
280
+ // "Blog post not found" text for a gateway failure.
281
+ const cause = (err as { cause?: unknown } | undefined)?.cause;
282
+ for (const failure of [cause, err]) {
283
+ if (isBridgeUnavailable(failure) || readWasUnreachable(failure)) throw failure;
284
+ }
285
+ }
286
+ for (const err of [postError, lastError]) {
287
+ // Non-transient access/validation failures keep their status too: the
288
+ // SDK's empty-query wrapper is not the reason this read failed.
289
+ const failure = (err as { cause?: unknown } | undefined)?.cause ?? err;
290
+ if (failure !== undefined && !isNotFound(failure)) throw failure;
281
291
  }
282
292
  // Wix says it is gone on BOTH reads (a published-only post's draft read is a 404 on its
283
293
  // own): its cached row must not outlive it, or an offline load repaints a deleted post.
@@ -361,7 +371,8 @@ const svc = defineService<PostState, {
361
371
  } catch (e) {
362
372
  // Offline: fall back to the last-synced local row before the demo/error paths.
363
373
  // Wix says it is gone (e.g. a delete whose reply was lost): drop the row, never show it.
364
- const cached = isNotFound(e) ? (await cacheDrop(id), null) : await cacheGet(id);
374
+ const cached = isNotFound(e) ? (await cacheDrop(id), null)
375
+ : readWasUnreachable(e) || isBridgeUnavailable(e) ? await cacheGet(id) : null;
365
376
  if (cached) return cachedDetail(s, cached);
366
377
  if (ownerDemoFallback(e)) {
367
378
  const demo = demoDetail(s, id);
@@ -385,7 +396,8 @@ const svc = defineService<PostState, {
385
396
  return loaded;
386
397
  } catch (e) {
387
398
  // Wix says it is gone (e.g. a delete whose reply was lost): drop the row, never show it.
388
- const cached = isNotFound(e) ? (await cacheDrop(s.id), null) : await cacheGet(s.id);
399
+ const cached = isNotFound(e) ? (await cacheDrop(s.id), null)
400
+ : readWasUnreachable(e) || isBridgeUnavailable(e) ? await cacheGet(s.id) : null;
389
401
  if (cached) return cachedDetail(s, cached);
390
402
  if (ownerDemoFallback(e)) {
391
403
  const demo = demoDetail(s, s.id);
@@ -293,6 +293,13 @@ export default defineApp({
293
293
  "parentScreenId": "himi_programs",
294
294
  "tabId": ""
295
295
  },
296
+ {
297
+ "screenId": "himi_member_programs",
298
+ "isPublic": true,
299
+ "paramKeys": [],
300
+ "parentScreenId": "himi_programs",
301
+ "tabId": ""
302
+ },
296
303
  {
297
304
  "screenId": "himi_plans",
298
305
  "isPublic": true,