@wix/himalaya-cli 0.1387.0 → 0.1388.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 (56) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/video/src/display.d.ts +66 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/video/src/index.d.ts +185 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-video.mjs +324 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
  5. package/dist/cli.mjs +5 -2
  6. package/guides/importable-sdks.md +1 -0
  7. package/guides/sdk-reference.json +253 -0
  8. package/package.json +2 -2
  9. package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +1 -1
  10. package/templates/beauty-salon/tier5-src/_shared/video-caption.ts +21 -0
  11. package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +31 -1
  12. package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +1 -1
  13. package/templates/branded-lite/dev/index.ts +982 -16
  14. package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +1 -1
  15. package/templates/branded-lite/tier5-src/_shared/video-caption.ts +21 -0
  16. package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +31 -1
  17. package/templates/branded-lite/tier5-src/himi-branded-lite-video/index.ts +23 -32
  18. package/templates/branded-lite/tier5-src/himi-branded-lite-videos/index.ts +44 -38
  19. package/templates/community-club/tier5-src/_shared/collection-contract.ts +1 -1
  20. package/templates/community-club/tier5-src/_shared/video-caption.ts +21 -0
  21. package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +31 -1
  22. package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +1 -1
  23. package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +1 -1
  24. package/templates/events-meetups/tier5-src/_shared/video-caption.ts +21 -0
  25. package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +31 -1
  26. package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +1 -1
  27. package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +1 -1
  28. package/templates/gym-fitness/tier5-src/_shared/video-caption.ts +21 -0
  29. package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +31 -1
  30. package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +1 -1
  31. package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +1 -1
  32. package/templates/nonprofit-cause/tier5-src/_shared/video-caption.ts +21 -0
  33. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +31 -1
  34. package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +1 -1
  35. package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +1 -1
  36. package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +1 -1
  37. package/templates/podcast-creator/tier5-src/_shared/video-caption.ts +21 -0
  38. package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +31 -1
  39. package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +1 -1
  40. package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +1 -1
  41. package/templates/portfolio-creative/tier5-src/_shared/video-caption.ts +21 -0
  42. package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +31 -1
  43. package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +1 -1
  44. package/templates/restaurant/tier5-src/_shared/collection-contract.ts +1 -1
  45. package/templates/restaurant/tier5-src/_shared/video-caption.ts +21 -0
  46. package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +31 -1
  47. package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +1 -1
  48. package/templates/retail-store/tier5-src/_shared/collection-contract.ts +1 -1
  49. package/templates/retail-store/tier5-src/_shared/video-caption.ts +21 -0
  50. package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +31 -1
  51. package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +1 -1
  52. package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +1 -1
  53. package/templates/yoga-studio/tier5-src/_shared/video-caption.ts +21 -0
  54. package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +31 -1
  55. package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +1 -1
  56. package/templates/branded-lite/tier5-src/_shared/vod.ts +0 -71
@@ -24613,6 +24613,259 @@
24613
24613
  }
24614
24614
  ]
24615
24615
  },
24616
+ {
24617
+ "name": "@himalaya/wix-video",
24618
+ "source": "stdlib/wix-sdk/video/src/index.ts",
24619
+ "description": "Wix Video — channels, videos, covers, durations, playback (native apps; the web bridges refuse its gateway)",
24620
+ "api": [
24621
+ {
24622
+ "name": "isHostedVideo",
24623
+ "kind": "function",
24624
+ "jsdoc": "/** True for a video whose file Wix hosts (it plays through `getVideoStreamUrl`). */",
24625
+ "decl": "export function isHostedVideo(video: WixVideo): boolean;"
24626
+ },
24627
+ {
24628
+ "name": "isVideoReady",
24629
+ "kind": "function",
24630
+ "jsdoc": "/** True when the video is published AND its media is ready to play. */",
24631
+ "decl": "export function isVideoReady(video: WixVideo): boolean;"
24632
+ },
24633
+ {
24634
+ "name": "isVideoProcessing",
24635
+ "kind": "function",
24636
+ "jsdoc": "/** True while an upload is still being processed (try again later). */",
24637
+ "decl": "export function isVideoProcessing(video: WixVideo): boolean;"
24638
+ },
24639
+ {
24640
+ "name": "youtubeVideoId",
24641
+ "kind": "function",
24642
+ "jsdoc": "/** The 11-character YouTube id of a linked YouTube video, or \"\". The embed URL is\n * treated as data: only the id is taken, never the URL itself. */",
24643
+ "decl": "export function youtubeVideoId(video: WixVideo): string;"
24644
+ },
24645
+ {
24646
+ "name": "videoCoverUrl",
24647
+ "kind": "function",
24648
+ "jsdoc": "/**\n * The video's card image, sized for display: the owner's cover, then the poster, then\n * the media thumbnail, then (for a YouTube video) YouTube's own thumbnail. \"\" when there\n * is none, so a card can show its placeholder.\n *\n * Wix media goes through `wixMediaUrl`: a stored cover is the untouched upload.\n */",
24649
+ "decl": "export function videoCoverUrl(video: WixVideo, size: WixImageSize | null = WIX_LIST_IMAGE): string;"
24650
+ },
24651
+ {
24652
+ "name": "channelCoverUrl",
24653
+ "kind": "function",
24654
+ "jsdoc": "/** The channel's cover image, sized for display, or \"\". */",
24655
+ "decl": "export function channelCoverUrl(channel: WixVideoChannel, size: WixImageSize | null = WIX_LIST_IMAGE): string;"
24656
+ },
24657
+ {
24658
+ "name": "videoDurationSec",
24659
+ "kind": "function",
24660
+ "jsdoc": "/** The video's length in whole seconds, or undefined when the gateway gives none. */",
24661
+ "decl": "export function videoDurationSec(video: WixVideo): number | undefined;"
24662
+ },
24663
+ {
24664
+ "name": "formatVideoDuration",
24665
+ "kind": "function",
24666
+ "jsdoc": "/** \"0:23\", \"4:05\", \"1:02:03\". \"\" for an unknown length. */",
24667
+ "decl": "export function formatVideoDuration(seconds: number | undefined): string;"
24668
+ },
24669
+ {
24670
+ "name": "isPaidVideo",
24671
+ "kind": "function",
24672
+ "jsdoc": "/** True when the video has an enabled SALE or RENT price. */",
24673
+ "decl": "export function isPaidVideo(video: WixVideo): boolean;"
24674
+ },
24675
+ {
24676
+ "name": "canWatchVideo",
24677
+ "kind": "function",
24678
+ "jsdoc": "/**\n * May the current viewer watch this video? FAILS CLOSED: missing pricing on the channel\n * or the video, or an entitlement that cannot be established, is \"no\".\n *\n * A channel with a required subscription or a pricing plan needs an active (or a\n * cancelled but unexpired) subscription. A paid video needs that subscription or its\n * own active sale or rent purchase. Query the channel with `CHANNEL_ACCESS_FIELDS` and\n * the video with `VIDEO_FIELDS`.\n */",
24679
+ "decl": "export function canWatchVideo(channel: WixVideoChannel, video: WixVideo, now = Date.now()): boolean;"
24680
+ },
24681
+ {
24682
+ "name": "latestVideos",
24683
+ "kind": "function",
24684
+ "jsdoc": "/**\n * Up to `limit` ready videos from the channels' preview pages (`listChannels` with\n * `videosPerChannel`, or `listLatestVideos`). Channels take turns — the first video of\n * each channel, then the second of each, … — so one large channel cannot fill the\n * whole rail. Duplicates (one video in two channels) appear once.\n */",
24685
+ "decl": "export function latestVideos(channels: WixVideoChannel[], limit = 8): WixVideoInChannel[];"
24686
+ },
24687
+ {
24688
+ "name": "WixVideoCard",
24689
+ "kind": "interface",
24690
+ "jsdoc": "/** The fields a video card binds to (`$item.*`). Shared by every carousel layout so the\n * caption placement is a layout choice, never a data change. */",
24691
+ "decl": "export interface WixVideoCard {\n id: string;\n channelId: string;\n title: string;\n /** \"4:05 · Channel\" — the parts that are known, joined. */\n meta: string;\n /** \"4:05\", or \"\". */\n duration: string;\n channelTitle: string;\n coverUrl: string;\n hasCover: boolean;\n noCover: boolean;\n /** True for a paid video (it may ask the viewer to buy or subscribe). */\n isPaid: boolean;\n notPaid: boolean;\n /** One spoken label: title, length and channel. */\n accessibilityLabel: string;\n}"
24692
+ },
24693
+ {
24694
+ "name": "videoCard",
24695
+ "kind": "function",
24696
+ "jsdoc": "/** Shape one video for a card. `untitled` replaces an empty title. */",
24697
+ "decl": "export function videoCard(entry: WixVideoInChannel, untitled = \"Video\", size: WixImageSize | null = WIX_LIST_IMAGE): WixVideoCard;"
24698
+ },
24699
+ {
24700
+ "name": "WIX_VIDEO_GRAPHQL_URL",
24701
+ "kind": "const",
24702
+ "jsdoc": "/** The Wix Video GraphQL gateway (visitor and member reads). */",
24703
+ "decl": "export const WIX_VIDEO_GRAPHQL_URL = \"https://manage.wix.com/_api/vod/public/graphql\";"
24704
+ },
24705
+ {
24706
+ "name": "WixCallOptions",
24707
+ "kind": "interface",
24708
+ "jsdoc": "/** Per-call options. `site` reads a business other than the app's active one. */",
24709
+ "decl": "export interface WixCallOptions {\n site?: string;\n}"
24710
+ },
24711
+ {
24712
+ "name": "WixVideoPricing",
24713
+ "kind": "interface",
24714
+ "jsdoc": "/** One price option of a channel (`SUBSCRIPTION` | `PRICING_PLAN`) or a video (`SALE` | `RENT`). */",
24715
+ "decl": "export interface WixVideoPricing {\n type?: string;\n enabled?: boolean;\n /** Channel only: true when every video needs the subscription or plan. */\n required?: boolean;\n price?: number;\n currency?: string;\n /** Rent period in hours (video) or subscription period (channel). */\n period?: number;\n}"
24716
+ },
24717
+ {
24718
+ "name": "WixVideoPurchase",
24719
+ "kind": "interface",
24720
+ "jsdoc": "/** The viewer's purchase of a channel subscription or of one video. */",
24721
+ "decl": "export interface WixVideoPurchase {\n /** `ACTIVE` | `PENDING` | `CANCELED` | `EXPIRED` | … */\n status?: string;\n expiresAt?: string;\n}"
24722
+ },
24723
+ {
24724
+ "name": "WixVideoMedia",
24725
+ "kind": "interface",
24726
+ "jsdoc": "/** The uploaded or linked media of a video. */",
24727
+ "decl": "export interface WixVideoMedia {\n /** `READY` once the file can play; `IN_QUEUE` / `IN_PROGRESS` / … while it processes. */\n status?: string;\n /** Length in milliseconds. */\n duration?: number;\n thumbnailUrl?: string;\n /** The embed URL of a linked (YouTube, Vimeo, …) video. */\n externalUrl?: string;\n externalId?: string;\n}"
24728
+ },
24729
+ {
24730
+ "name": "WixVideoImage",
24731
+ "kind": "interface",
24732
+ "jsdoc": "/** A selectable image (cover or poster). `selected` is the image URL. */",
24733
+ "decl": "export interface WixVideoImage {\n selected?: string | null;\n}"
24734
+ },
24735
+ {
24736
+ "name": "WixVideoPage",
24737
+ "kind": "interface",
24738
+ "jsdoc": "/** A page of a paginated list. */",
24739
+ "decl": "export interface WixVideoPage<T> {\n total?: number;\n cursor?: string | null;\n entities?: T[];\n}"
24740
+ },
24741
+ {
24742
+ "name": "WixVideo",
24743
+ "kind": "interface",
24744
+ "jsdoc": "",
24745
+ "decl": "export interface WixVideo {\n id: string;\n title?: string;\n description?: string;\n publisher?: string;\n /** `COMPUTER` | `GOOGLE_DRIVE` | `DROPBOX` (hosted) | `YOUTUBE` | `VIMEO` | `FACEBOOK` | `LIVE`. */\n source?: string;\n /** `VISIBLE` for a published video. */\n status?: string;\n cover?: WixVideoImage | null;\n poster?: WixVideoImage | null;\n content?: WixVideoMedia | null;\n pricing?: WixVideoPricing[];\n /** The viewer's SALE purchase, when the query asks for it. */\n purchase?: WixVideoPurchase | null;\n /** The viewer's RENT purchase, when the query asks for it (GraphQL alias). */\n rent_purchase?: WixVideoPurchase | null;\n}"
24746
+ },
24747
+ {
24748
+ "name": "WixVideoChannel",
24749
+ "kind": "interface",
24750
+ "jsdoc": "",
24751
+ "decl": "export interface WixVideoChannel {\n id: string;\n title?: string;\n description?: string;\n /** `INTERNAL` | `YOUTUBE`. */\n source?: string;\n featuredVideoId?: string | null;\n hasPaidVideos?: boolean;\n cover?: WixVideoImage | null;\n pricing?: WixVideoPricing[];\n /** The viewer's SUBSCRIPTION purchase, when the query asks for it. */\n purchase?: WixVideoPurchase | null;\n /** The channel's videos: only `total` in a list, a page when the query asks for one. */\n videos?: WixVideoPage<WixVideo>;\n}"
24752
+ },
24753
+ {
24754
+ "name": "WixVideoInChannel",
24755
+ "kind": "interface",
24756
+ "jsdoc": "/** A video together with the channel it belongs to. */",
24757
+ "decl": "export interface WixVideoInChannel {\n channel: WixVideoChannel;\n video: WixVideo;\n}"
24758
+ },
24759
+ {
24760
+ "name": "WixVideoErrorFlags",
24761
+ "kind": "interface",
24762
+ "jsdoc": "/** Flags every error this client throws carries, so a caller can branch without\n * matching message text. */",
24763
+ "decl": "export interface WixVideoErrorFlags {\n /** The gateway refused the viewer (membership, purchase or permission). */\n denied: boolean;\n /** The gateway needs a signed-in member. */\n signInRequired: boolean;\n /** The requested channel does not exist or is not visible. */\n notFound: boolean;\n}"
24764
+ },
24765
+ {
24766
+ "name": "WixVideoError",
24767
+ "kind": "type",
24768
+ "jsdoc": "",
24769
+ "decl": "export type WixVideoError = Error & WixVideoErrorFlags;"
24770
+ },
24771
+ {
24772
+ "name": "wixVideoError",
24773
+ "kind": "function",
24774
+ "jsdoc": "/** Build an error carrying the `WixVideoErrorFlags` (each defaults to false). */",
24775
+ "decl": "export function wixVideoError(message: string, flags: Partial<WixVideoErrorFlags> = {}): WixVideoError;"
24776
+ },
24777
+ {
24778
+ "name": "isWixVideoWebRefusal",
24779
+ "kind": "function",
24780
+ "jsdoc": "/** True when a web bridge refused the gateway URL. Wix Video is then out of reach on\n * this surface: the same read works in the native apps. */",
24781
+ "decl": "export function isWixVideoWebRefusal(error: unknown): boolean;"
24782
+ },
24783
+ {
24784
+ "name": "wixVideoQuery",
24785
+ "kind": "function",
24786
+ "jsdoc": "/**\n * Run one GraphQL read against the Wix Video gateway and return its `data`.\n *\n * The gateway answers HTTP 200 with an `errors` array for a refused or failed query.\n * That is thrown, never returned as empty data: a failed query must not look like a\n * site with no videos.\n *\n * @scope visitor\n */",
24787
+ "decl": "export async function wixVideoQuery<T>(query: string, variables: Record<string, unknown> = {}, opts?: WixCallOptions): Promise<T>;",
24788
+ "scope": "visitor"
24789
+ },
24790
+ {
24791
+ "name": "wixVideoPages",
24792
+ "kind": "function",
24793
+ "jsdoc": "/** Read every page of a cursor-paginated list. Rows are de-duplicated by id. A\n * repeated or malformed cursor throws instead of looping or returning a partial list. */",
24794
+ "decl": "export async function wixVideoPages<T extends { id: string }>(\n fetchPage: (cursor: string | null) => Promise<WixVideoPage<T> | null | undefined>,\n): Promise<T[]>;"
24795
+ },
24796
+ {
24797
+ "name": "CHANNEL_FIELDS",
24798
+ "kind": "const",
24799
+ "jsdoc": "/** The channel fields a list or card needs. */",
24800
+ "decl": "export const CHANNEL_FIELDS = \"id title description source featuredVideoId hasPaidVideos cover { selected } videos { total }\";"
24801
+ },
24802
+ {
24803
+ "name": "CHANNEL_ACCESS_FIELDS",
24804
+ "kind": "const",
24805
+ "jsdoc": "/** The channel fields an access decision needs (`canWatchVideo`). */",
24806
+ "decl": "export const CHANNEL_ACCESS_FIELDS = \"id title pricing { type enabled required } purchase(filter: {type: SUBSCRIPTION}) { status expiresAt }\";"
24807
+ },
24808
+ {
24809
+ "name": "VIDEO_CARD_FIELDS",
24810
+ "kind": "const",
24811
+ "jsdoc": "/** The video fields a card needs: title, images, length and processing state. */",
24812
+ "decl": "export const VIDEO_CARD_FIELDS = \"id title source status cover { selected } poster { selected } content { status duration thumbnailUrl externalUrl externalId } pricing { type enabled }\";"
24813
+ },
24814
+ {
24815
+ "name": "VIDEO_FIELDS",
24816
+ "kind": "const",
24817
+ "jsdoc": "/** The video fields playback and an access decision need. */",
24818
+ "decl": "export const VIDEO_FIELDS = \"id title description source status cover { selected } poster { selected } content { status duration thumbnailUrl externalUrl externalId } pricing { type enabled } purchase(filter: {type: SALE}) { status } rent_purchase: purchase(filter: {type: RENT}) { status }\";"
24819
+ },
24820
+ {
24821
+ "name": "ListChannelsOptions",
24822
+ "kind": "interface",
24823
+ "jsdoc": "",
24824
+ "decl": "export interface ListChannelsOptions extends WixCallOptions {\n /** Also read the first N videos of each channel (owner's order). 0 (default) reads none. */\n videosPerChannel?: number;\n}"
24825
+ },
24826
+ {
24827
+ "name": "listChannels",
24828
+ "kind": "function",
24829
+ "jsdoc": "/**\n * Every channel of the site, in the owner's order (all pages).\n *\n * @scope visitor\n */",
24830
+ "decl": "export async function listChannels(opts: ListChannelsOptions = {}): Promise<WixVideoChannel[]>;",
24831
+ "scope": "visitor"
24832
+ },
24833
+ {
24834
+ "name": "listChannelVideos",
24835
+ "kind": "function",
24836
+ "jsdoc": "/**\n * One channel and all its videos, in the owner's order. Throws a `notFound` error when\n * the channel does not exist.\n *\n * @scope visitor\n */",
24837
+ "decl": "export async function listChannelVideos(channelId: string, opts?: WixCallOptions): Promise<{ channel: WixVideoChannel; videos: WixVideo[] }>;",
24838
+ "scope": "visitor"
24839
+ },
24840
+ {
24841
+ "name": "getVideo",
24842
+ "kind": "function",
24843
+ "jsdoc": "/**\n * One video with its channel's access fields. `null` when the channel does not exist;\n * `video: null` when the channel has no such video.\n *\n * @scope visitor\n */",
24844
+ "decl": "export async function getVideo(channelId: string, videoId: string, opts?: WixCallOptions): Promise<{ channel: WixVideoChannel; video: WixVideo | null } | null>;",
24845
+ "scope": "visitor"
24846
+ },
24847
+ {
24848
+ "name": "getVideoStreamUrl",
24849
+ "kind": "function",
24850
+ "jsdoc": "/**\n * An authorized HLS stream URL for a hosted video (source `COMPUTER`, `GOOGLE_DRIVE`\n * or `DROPBOX`), or \"\" when the gateway gives none. Check `canWatchVideo` first: the\n * gateway authorizes the stream per viewer. A linked (YouTube, …) video has no stream\n * here; use `youtubeVideoId`.\n *\n * @scope visitor\n */",
24851
+ "decl": "export async function getVideoStreamUrl(channelId: string, videoId: string, opts?: WixCallOptions): Promise<string>;",
24852
+ "scope": "visitor"
24853
+ },
24854
+ {
24855
+ "name": "ListLatestVideosOptions",
24856
+ "kind": "interface",
24857
+ "jsdoc": "",
24858
+ "decl": "export interface ListLatestVideosOptions extends WixCallOptions {\n /** Most videos to return (default 8). */\n limit?: number;\n /** Channels to read (first page, default 10). */\n channels?: number;\n /** Videos to read from each channel (default 4). */\n perChannel?: number;\n}"
24859
+ },
24860
+ {
24861
+ "name": "listLatestVideos",
24862
+ "kind": "function",
24863
+ "jsdoc": "/**\n * The newest ready videos across the site's channels, for a rail or carousel: ONE\n * request that reads the first videos of the first channels. Channel order and each\n * channel's own video order are kept, and the channels take turns, so one large\n * channel cannot fill the whole rail.\n *\n * @scope visitor\n */",
24864
+ "decl": "export async function listLatestVideos(opts: ListLatestVideosOptions = {}): Promise<WixVideoInChannel[]>;",
24865
+ "scope": "visitor"
24866
+ }
24867
+ ]
24868
+ },
24616
24869
  {
24617
24870
  "name": "@himalaya/wix-workflows",
24618
24871
  "source": "stdlib/wix-sdk/workflows-v1/src/index.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1387.0",
3
+ "version": "0.1388.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": "3775f6901bf78a5a41956aac4c29f84e7abbb7149aa95c4bf7552269"
74
+ "falconPackageHash": "6ea552221f975dd6438104d636817ced2f4d49d9cbb69e0e8501fb91"
75
75
  }
@@ -98,7 +98,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
98
98
  himiBrandedBadges: { rows: 'badges', title: 'name', subtitle: 'description', view: 'grid' },
99
99
  himiBrandedDonations: { rows: 'campaigns', title: 'name', subtitle: 'description', view: 'grid', primaryVerb: { label: 'Donate' } },
100
100
  himiBrandedGiftCards: { rows: 'cards', title: 'name', subtitle: 'description', view: 'grid' },
101
- himiBrandedVideos: { rows: 'channels', title: 'title', subtitle: 'description', view: 'grid' },
101
+ himiBrandedVideos: { rows: 'channels', title: 'title', subtitle: 'subtitle', image: 'coverUrl', view: 'grid', searchPlaceholder: 'Search channels', countNoun: ['channel', 'channels'] },
102
102
  himiBrandedPodcasts: { rows: 'episodes', title: 'title', subtitle: 'subtitle', image: 'image', metadata: ['progressLabel'], view: 'list' },
103
103
  himiBrandedForms: { rows: 'forms', title: 'name', subtitle: 'description', view: 'list' },
104
104
  himiBrandedGalleries: { rows: 'galleries', title: 'name', subtitle: 'description', image: 'image', view: 'grid' },
@@ -0,0 +1,21 @@
1
+ // The video carousel's two looks: the caption ON the cover (a brand label chip over the
2
+ // image) or UNDER it. Every slide carries both placements; the descriptor's
3
+ // `videoCaption` appear param picks one, and these flags hide the other
4
+ // (`hiddenWhen` hides on TRUE). So a screen switches look by changing ONE param,
5
+ // with no second carousel and no change to the slide tree.
6
+ export type VideoCaption = "overlay" | "below";
7
+
8
+ /** The placement a param asks for. Anything but "below" is the default, "overlay". */
9
+ export function videoCaptionOf(value: unknown): VideoCaption {
10
+ return value === "below" ? "below" : "overlay";
11
+ }
12
+
13
+ export interface CaptionFlags {
14
+ captionOnImage: boolean;
15
+ captionBelow: boolean;
16
+ }
17
+
18
+ /** Stamp each card with the gates its slide reads (`$item.captionOnImage` / `$item.captionBelow`). */
19
+ export function withCaption<T extends object>(cards: T[], caption: VideoCaption): (T & CaptionFlags)[] {
20
+ return cards.map((card) => ({ ...card, captionOnImage: caption === "overlay", captionBelow: caption === "below" }));
21
+ }
@@ -22,12 +22,18 @@ import { formatDateMedium } from "../_shared/engine-intl.js";
22
22
  import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-saved.js";
23
23
  import { readSavedIds } from "../_shared/himi-blog-saved.js";
24
24
  import { wixMediaUrl } from "@himalaya/wix-media";
25
+ import { isWixVideoWebRefusal, listLatestVideos, videoCard, type WixVideoCard } from "@himalaya/wix-video";
26
+ import { videoCaptionOf, withCaption, type CaptionFlags } from "../_shared/video-caption.js";
25
27
 
26
28
  /** Latched once the member feed is refused because of WHERE the app is running rather
27
29
  * than because of the request — see the catch in `loadExtras`. Module scope, so it
28
30
  * survives every refresh of this worker and is reset only by a fresh boot. */
29
31
  let feedSurfaceRefused = false;
30
32
 
33
+ /** The same latch for Wix Video: its gateway is reachable from the native apps only, so a
34
+ * web bridge's refusal is permanent for this boot and the rail stays collapsed. */
35
+ let videoSurfaceRefused = false;
36
+
31
37
  /** True for the one refusal that can never change while the app keeps running: the web
32
38
  * bridge reporting that this host is not reachable from a browser at all. Deliberately
33
39
  * narrower than `isBridgeUnavailable` — a 502/503 is an outage worth retrying, and only
@@ -292,6 +298,10 @@ interface State {
292
298
  noNextEvent: boolean;
293
299
  homePrograms: ProgramCard[];
294
300
  noHomePrograms: boolean;
301
+ /** The videos module's carousel — the newest ready Wix Video videos, the channels
302
+ * taking turns. Guarded on `videos`; same silent-fail contract. */
303
+ homeVideos: (WixVideoCard & CaptionFlags)[];
304
+ noHomeVideos: boolean;
295
305
  feedHighlights: FeedHighlight[];
296
306
  noFeedHighlights: boolean;
297
307
  /** communityPulse member strip — the author directory of the SAME feed read
@@ -529,6 +539,7 @@ interface ExtrasSignal {
529
539
  upcomingEvents: EventEntry[];
530
540
  nextEventCards: NextEventCard[];
531
541
  homePrograms: ProgramCard[];
542
+ homeVideos: (WixVideoCard & CaptionFlags)[];
532
543
  feedHighlights: FeedHighlight[];
533
544
  memberAvatars: CoachAvatar[];
534
545
  groupCards: GroupCard[];
@@ -539,7 +550,7 @@ interface ExtrasSignal {
539
550
  }
540
551
 
541
552
  function emptyExtrasSignal(): ExtrasSignal {
542
- return { upcomingEvents: [], nextEventCards: [], homePrograms: [], feedHighlights: [], memberAvatars: [], groupCards: [], announcementTitle: "", postCards: [], popularDishes: [], menuCategories: [] };
553
+ return { upcomingEvents: [], nextEventCards: [], homePrograms: [], homeVideos: [], feedHighlights: [], memberAvatars: [], groupCards: [], announcementTitle: "", postCards: [], popularDishes: [], menuCategories: [] };
543
554
  }
544
555
 
545
556
  /** Cover URL probe for a blog post — the himi-blog-feed imageUrl fallbacks
@@ -679,6 +690,18 @@ async function fetchHomePrograms(): Promise<ProgramCard[]> {
679
690
  }
680
691
  }
681
692
 
693
+ /** ONE Wix Video read for the videos module. A failure collapses the module; the web
694
+ * bridges' refusal of the gateway also latches it off for the rest of this boot. */
695
+ async function fetchHomeVideos(): Promise<WixVideoCard[]> {
696
+ try {
697
+ const untitled = copyParam("home.videoFallbackTitle", "Video");
698
+ return (await listLatestVideos({ limit: 8 })).map((entry) => videoCard(entry, untitled));
699
+ } catch (error) {
700
+ if (isWixVideoWebRefusal(error)) videoSurfaceRefused = true;
701
+ return [];
702
+ }
703
+ }
704
+
682
705
  function homeFeedText(item: WixFeedItem): string {
683
706
  const blocks = item.content?.blocks;
684
707
  if (Array.isArray(blocks)) {
@@ -731,6 +754,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
731
754
  if (verticals.includes("programs")) {
732
755
  jobs.push(fetchHomePrograms().then((cards) => { extras.homePrograms = cards; }));
733
756
  }
757
+ if (verticals.includes("videos") && !videoSurfaceRefused) {
758
+ const caption = videoCaptionOf(paramValue(arg, "videoCaption"));
759
+ jobs.push(fetchHomeVideos().then((cards) => { extras.homeVideos = withCaption(cards, caption); }));
760
+ }
734
761
  if (verticals.includes("blog")) {
735
762
  // ONE limit-8 posts query feeds BOTH the communityPulse announcement
736
763
  // (posts[0].title — the frozen contract) and the showcaseFirst/episodeFirst
@@ -847,6 +874,7 @@ function derive(state: State): State {
847
874
  noUpcomingEvents: state.upcomingEvents.length === 0,
848
875
  noNextEvent: state.nextEventCards.length === 0,
849
876
  noHomePrograms: state.homePrograms.length === 0,
877
+ noHomeVideos: state.homeVideos.length === 0,
850
878
  noFeedHighlights: state.feedHighlights.length === 0,
851
879
  noMemberAvatars: state.memberAvatars.length === 0,
852
880
  noGroupCards: state.groupCards.length === 0,
@@ -938,6 +966,8 @@ function baseState(): State {
938
966
  noNextEvent: true,
939
967
  homePrograms: [],
940
968
  noHomePrograms: true,
969
+ homeVideos: [],
970
+ noHomeVideos: true,
941
971
  feedHighlights: [],
942
972
  noFeedHighlights: true,
943
973
  memberAvatars: [],
@@ -98,7 +98,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
98
98
  himiBrandedBadges: { rows: 'badges', title: 'name', subtitle: 'description', view: 'grid' },
99
99
  himiBrandedDonations: { rows: 'campaigns', title: 'name', subtitle: 'description', view: 'grid', primaryVerb: { label: 'Donate' } },
100
100
  himiBrandedGiftCards: { rows: 'cards', title: 'name', subtitle: 'description', view: 'grid' },
101
- himiBrandedVideos: { rows: 'channels', title: 'title', subtitle: 'description', view: 'grid' },
101
+ himiBrandedVideos: { rows: 'channels', title: 'title', subtitle: 'subtitle', image: 'coverUrl', view: 'grid', searchPlaceholder: 'Search channels', countNoun: ['channel', 'channels'] },
102
102
  himiBrandedPodcasts: { rows: 'episodes', title: 'title', subtitle: 'subtitle', image: 'image', metadata: ['progressLabel'], view: 'list' },
103
103
  himiBrandedForms: { rows: 'forms', title: 'name', subtitle: 'description', view: 'list' },
104
104
  himiBrandedGalleries: { rows: 'galleries', title: 'name', subtitle: 'description', image: 'image', view: 'grid' },