@wix/himalaya-cli 0.1387.0 → 0.1389.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-contract.d.ts +24 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-core.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/index.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/video/src/display.d.ts +66 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/video/src/index.d.ts +185 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +57 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +57 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-video.mjs +324 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
- package/dist/cli.mjs +10 -5
- package/guides/iap-screen-adoption.md +53 -1
- package/guides/importable-sdks.md +1 -0
- package/guides/sdk-reference.json +261 -2
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +193 -1
- package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/beauty-salon/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/beauty-salon/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/beauty-salon-owner/config.ts +11 -0
- package/templates/beauty-salon-owner/dev/index.ts +540 -0
- package/templates/beauty-salon-owner/himalaya.content.json +6 -0
- package/templates/beauty-salon-owner/platforms.json +2 -1
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/branded-lite/dev/index.ts +1212 -54
- package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/branded-lite/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/branded-lite/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-video/index.ts +23 -32
- package/templates/branded-lite/tier5-src/himi-branded-lite-videos/index.ts +44 -38
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/community-club/dev/index.ts +193 -1
- package/templates/community-club/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/community-club/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/community-club/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/community-club/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/community-club-owner/config.ts +11 -0
- package/templates/community-club-owner/dev/index.ts +540 -0
- package/templates/community-club-owner/himalaya.content.json +6 -0
- package/templates/community-club-owner/platforms.json +2 -1
- package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/community-club-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/events-meetups/dev/index.ts +193 -1
- package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/events-meetups/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/events-meetups/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/events-meetups-owner/config.ts +11 -0
- package/templates/events-meetups-owner/dev/index.ts +540 -0
- package/templates/events-meetups-owner/himalaya.content.json +6 -0
- package/templates/events-meetups-owner/platforms.json +2 -1
- package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/gym-fitness/dev/index.ts +193 -1
- package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/gym-fitness/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/gym-fitness/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/gym-fitness-owner/config.ts +11 -0
- package/templates/gym-fitness-owner/dev/index.ts +540 -0
- package/templates/gym-fitness-owner/himalaya.content.json +6 -0
- package/templates/gym-fitness-owner/platforms.json +2 -1
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/nonprofit-cause/dev/index.ts +193 -1
- package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/nonprofit-cause/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/nonprofit-cause/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/nonprofit-cause-owner/config.ts +11 -0
- package/templates/nonprofit-cause-owner/dev/index.ts +540 -0
- package/templates/nonprofit-cause-owner/himalaya.content.json +6 -0
- package/templates/nonprofit-cause-owner/platforms.json +2 -1
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/owner-lite/config.ts +11 -0
- package/templates/owner-lite/dev/index.ts +540 -0
- package/templates/owner-lite/himalaya.content.json +6 -0
- package/templates/owner-lite/platforms.json +2 -1
- package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/owner-lite/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/podcast-creator/dev/index.ts +193 -1
- package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/podcast-creator/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/podcast-creator/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/podcast-creator-owner/config.ts +11 -0
- package/templates/podcast-creator-owner/dev/index.ts +540 -0
- package/templates/podcast-creator-owner/himalaya.content.json +6 -0
- package/templates/podcast-creator-owner/platforms.json +2 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/portfolio-creative/dev/index.ts +193 -1
- package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/portfolio-creative/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/portfolio-creative/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/portfolio-creative-owner/config.ts +11 -0
- package/templates/portfolio-creative-owner/dev/index.ts +540 -0
- package/templates/portfolio-creative-owner/himalaya.content.json +6 -0
- package/templates/portfolio-creative-owner/platforms.json +2 -1
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/restaurant/dev/index.ts +193 -1
- package/templates/restaurant/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/restaurant/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/restaurant/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/restaurant-owner/config.ts +11 -0
- package/templates/restaurant-owner/dev/index.ts +540 -0
- package/templates/restaurant-owner/himalaya.content.json +6 -0
- package/templates/restaurant-owner/platforms.json +2 -1
- package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/retail-store/dev/index.ts +193 -1
- package/templates/retail-store/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/retail-store/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/retail-store/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/retail-store-owner/config.ts +11 -0
- package/templates/retail-store-owner/dev/index.ts +540 -0
- package/templates/retail-store-owner/himalaya.content.json +6 -0
- package/templates/retail-store-owner/platforms.json +2 -1
- package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/yoga-studio/dev/index.ts +193 -1
- package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/yoga-studio/tier5-src/_shared/iap-worker.ts +84 -3
- package/templates/yoga-studio/tier5-src/_shared/video-caption.ts +21 -0
- package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +31 -1
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +36 -1
- package/templates/yoga-studio-owner/config.ts +11 -0
- package/templates/yoga-studio-owner/dev/index.ts +540 -0
- package/templates/yoga-studio-owner/himalaya.content.json +6 -0
- package/templates/yoga-studio-owner/platforms.json +2 -1
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-wrist/index.ts +350 -0
- package/templates/branded-lite/tier5-src/_shared/vod.ts +0 -71
|
@@ -50,6 +50,10 @@ export interface IapCommerce {
|
|
|
50
50
|
buy(item: IapOrderItem): Promise<AppleIapCheckoutState>;
|
|
51
51
|
/** On resume: re-reads Apple's unfinished queue and the payments being tracked. */
|
|
52
52
|
reconcile(): Promise<AppleIapCheckoutState>;
|
|
53
|
+
/** Restore purchases (App Review 3.1.1): syncs Apple's purchase history to the device, then makes a
|
|
54
|
+
* new attempt at every unfinished purchase (a scheduled retry is not waited out) and re-reads the
|
|
55
|
+
* member's access. Needs a signed-in member; taps while one runs share it. */
|
|
56
|
+
restore(): Promise<IapRestoreResult>;
|
|
53
57
|
tick(): Promise<AppleIapCheckoutState>;
|
|
54
58
|
/** The screen's one `_poll` for prices and purchase, or undefined when the cadence it already
|
|
55
59
|
* armed still holds (or there is nothing to poll). Emit it from every publish. */
|
|
@@ -59,6 +63,26 @@ export interface IapCommerce {
|
|
|
59
63
|
poll(): Promise<void>;
|
|
60
64
|
dispose(): void;
|
|
61
65
|
}
|
|
66
|
+
/** What a restore found. Counts only: never a product, transaction or member id.
|
|
67
|
+
* - `needsSignIn`: no member is signed in; Apple was not asked.
|
|
68
|
+
* - `restored`: `recovered` purchases were taken by Wix during this restore; `refused` stay held,
|
|
69
|
+
* unfinished, because Wix refused them (another member's purchase, say), plus any Wix refused for good
|
|
70
|
+
* during this restore (finished; the member needs support); `pending` are charged but
|
|
71
|
+
* not yet taken (Wix could not be reached, or asked to retry), and stay held for the next attempt.
|
|
72
|
+
* - `failed`: `storeUnavailable` when the App Store sync or Apple's queue could not be read,
|
|
73
|
+
* `unavailable` when this host does not sell through the App Store, `sessionChanged` when the
|
|
74
|
+
* member changed. */
|
|
75
|
+
export type IapRestoreResult = {
|
|
76
|
+
status: "needsSignIn";
|
|
77
|
+
} | {
|
|
78
|
+
status: "restored";
|
|
79
|
+
recovered: number;
|
|
80
|
+
refused: number;
|
|
81
|
+
pending: number;
|
|
82
|
+
} | {
|
|
83
|
+
status: "failed";
|
|
84
|
+
code: "storeUnavailable" | "unavailable" | "sessionChanged";
|
|
85
|
+
};
|
|
62
86
|
/** Labels from the screen's copy pack; the shared layer only chooses between them. */
|
|
63
87
|
export interface IapPurchaseCopy {
|
|
64
88
|
buy: string;
|
|
@@ -24,6 +24,9 @@ export interface IapCommerceDependencies {
|
|
|
24
24
|
identity: MemberIdentitySource;
|
|
25
25
|
host: CommerceHost;
|
|
26
26
|
store: TransactionStore;
|
|
27
|
+
/** StoreKit's `AppStore.sync()`: brings Apple's purchase history to the device and may ask the
|
|
28
|
+
* person to sign in to their Apple Account. Rejects when the App Store cannot be reached. */
|
|
29
|
+
syncAppStore(): Promise<void>;
|
|
27
30
|
refs: OrderRefStore;
|
|
28
31
|
clock: Clock;
|
|
29
32
|
adapters: readonly IapOrderAdapter[];
|
|
@@ -5,4 +5,4 @@ export { onlineProgramOrders, pricingPlanOrders, storesProductOrders, classifyCa
|
|
|
5
5
|
export { createWorkerOrderRefStore } from "./order-refs.js";
|
|
6
6
|
export { itemPaymentEnabled, storesAppleSalesEnabled } from "./checkout-source.js";
|
|
7
7
|
export type { AccessRead, AppleIapCheckout, AppleIapCheckoutDependencies, AppleIapCheckoutPhase, AppleIapCheckoutState, BridgeOutcome, BridgeRefusal, CashierRoute, IapEligibility, IapOrderAdapter, IapOrderItem, OrderAttempt, OrderFailureCode, OrderPartitionKey, OrderRef, OrderRefPartition, OrderRefStage, OrderRefStore, PaymentAccess, PaymentProgress, SessionBoundBridge, VerticalRef, WixBridge, } from "./apple-iap-contract.js";
|
|
8
|
-
export type { AppleIapCheckoutRoutes, IapCommerce, IapCommerceOptions, IapPurchaseCopy, IapPurchaseFields, IapPurchaseGap, IapPurchaseReadiness, } from "./commerce-contract.js";
|
|
8
|
+
export type { AppleIapCheckoutRoutes, IapCommerce, IapCommerceOptions, IapPurchaseCopy, IapPurchaseFields, IapPurchaseGap, IapPurchaseReadiness, IapRestoreResult, } from "./commerce-contract.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { WixVideo, WixVideoChannel, WixVideoInChannel } from "./index.js";
|
|
2
|
+
import { type WixImageSize } from "@wix/himalaya/wix-media";
|
|
3
|
+
/** True for a video whose file Wix hosts (it plays through `getVideoStreamUrl`). */
|
|
4
|
+
export declare function isHostedVideo(video: WixVideo): boolean;
|
|
5
|
+
/** True when the video is published AND its media is ready to play. */
|
|
6
|
+
export declare function isVideoReady(video: WixVideo): boolean;
|
|
7
|
+
/** True while an upload is still being processed (try again later). */
|
|
8
|
+
export declare function isVideoProcessing(video: WixVideo): boolean;
|
|
9
|
+
/** The 11-character YouTube id of a linked YouTube video, or "". The embed URL is
|
|
10
|
+
* treated as data: only the id is taken, never the URL itself. */
|
|
11
|
+
export declare function youtubeVideoId(video: WixVideo): string;
|
|
12
|
+
/**
|
|
13
|
+
* The video's card image, sized for display: the owner's cover, then the poster, then
|
|
14
|
+
* the media thumbnail, then (for a YouTube video) YouTube's own thumbnail. "" when there
|
|
15
|
+
* is none, so a card can show its placeholder.
|
|
16
|
+
*
|
|
17
|
+
* Wix media goes through `wixMediaUrl`: a stored cover is the untouched upload.
|
|
18
|
+
*/
|
|
19
|
+
export declare function videoCoverUrl(video: WixVideo, size?: WixImageSize | null): string;
|
|
20
|
+
/** The channel's cover image, sized for display, or "". */
|
|
21
|
+
export declare function channelCoverUrl(channel: WixVideoChannel, size?: WixImageSize | null): string;
|
|
22
|
+
/** The video's length in whole seconds, or undefined when the gateway gives none. */
|
|
23
|
+
export declare function videoDurationSec(video: WixVideo): number | undefined;
|
|
24
|
+
/** "0:23", "4:05", "1:02:03". "" for an unknown length. */
|
|
25
|
+
export declare function formatVideoDuration(seconds: number | undefined): string;
|
|
26
|
+
/** True when the video has an enabled SALE or RENT price. */
|
|
27
|
+
export declare function isPaidVideo(video: WixVideo): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* May the current viewer watch this video? FAILS CLOSED: missing pricing on the channel
|
|
30
|
+
* or the video, or an entitlement that cannot be established, is "no".
|
|
31
|
+
*
|
|
32
|
+
* A channel with a required subscription or a pricing plan needs an active (or a
|
|
33
|
+
* cancelled but unexpired) subscription. A paid video needs that subscription or its
|
|
34
|
+
* own active sale or rent purchase. Query the channel with `CHANNEL_ACCESS_FIELDS` and
|
|
35
|
+
* the video with `VIDEO_FIELDS`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function canWatchVideo(channel: WixVideoChannel, video: WixVideo, now?: number): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Up to `limit` ready videos from the channels' preview pages (`listChannels` with
|
|
40
|
+
* `videosPerChannel`, or `listLatestVideos`). Channels take turns — the first video of
|
|
41
|
+
* each channel, then the second of each, … — so one large channel cannot fill the
|
|
42
|
+
* whole rail. Duplicates (one video in two channels) appear once.
|
|
43
|
+
*/
|
|
44
|
+
export declare function latestVideos(channels: WixVideoChannel[], limit?: number): WixVideoInChannel[];
|
|
45
|
+
/** The fields a video card binds to (`$item.*`). Shared by every carousel layout so the
|
|
46
|
+
* caption placement is a layout choice, never a data change. */
|
|
47
|
+
export interface WixVideoCard {
|
|
48
|
+
id: string;
|
|
49
|
+
channelId: string;
|
|
50
|
+
title: string;
|
|
51
|
+
/** "4:05 · Channel" — the parts that are known, joined. */
|
|
52
|
+
meta: string;
|
|
53
|
+
/** "4:05", or "". */
|
|
54
|
+
duration: string;
|
|
55
|
+
channelTitle: string;
|
|
56
|
+
coverUrl: string;
|
|
57
|
+
hasCover: boolean;
|
|
58
|
+
noCover: boolean;
|
|
59
|
+
/** True for a paid video (it may ask the viewer to buy or subscribe). */
|
|
60
|
+
isPaid: boolean;
|
|
61
|
+
notPaid: boolean;
|
|
62
|
+
/** One spoken label: title, length and channel. */
|
|
63
|
+
accessibilityLabel: string;
|
|
64
|
+
}
|
|
65
|
+
/** Shape one video for a card. `untitled` replaces an empty title. */
|
|
66
|
+
export declare function videoCard(entry: WixVideoInChannel, untitled?: string, size?: WixImageSize | null): WixVideoCard;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export * from "./display.js";
|
|
2
|
+
declare global {
|
|
3
|
+
var himalaya: {
|
|
4
|
+
wixApi?: {
|
|
5
|
+
call: (method: string, path: string, body?: unknown, headers?: Record<string, string>) => Promise<unknown>;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** The Wix Video GraphQL gateway (visitor and member reads). */
|
|
10
|
+
export declare const WIX_VIDEO_GRAPHQL_URL = "https://manage.wix.com/_api/vod/public/graphql";
|
|
11
|
+
/** Per-call options. `site` reads a business other than the app's active one. */
|
|
12
|
+
export interface WixCallOptions {
|
|
13
|
+
site?: string;
|
|
14
|
+
}
|
|
15
|
+
/** One price option of a channel (`SUBSCRIPTION` | `PRICING_PLAN`) or a video (`SALE` | `RENT`). */
|
|
16
|
+
export interface WixVideoPricing {
|
|
17
|
+
type?: string;
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
/** Channel only: true when every video needs the subscription or plan. */
|
|
20
|
+
required?: boolean;
|
|
21
|
+
price?: number;
|
|
22
|
+
currency?: string;
|
|
23
|
+
/** Rent period in hours (video) or subscription period (channel). */
|
|
24
|
+
period?: number;
|
|
25
|
+
}
|
|
26
|
+
/** The viewer's purchase of a channel subscription or of one video. */
|
|
27
|
+
export interface WixVideoPurchase {
|
|
28
|
+
/** `ACTIVE` | `PENDING` | `CANCELED` | `EXPIRED` | … */
|
|
29
|
+
status?: string;
|
|
30
|
+
expiresAt?: string;
|
|
31
|
+
}
|
|
32
|
+
/** The uploaded or linked media of a video. */
|
|
33
|
+
export interface WixVideoMedia {
|
|
34
|
+
/** `READY` once the file can play; `IN_QUEUE` / `IN_PROGRESS` / … while it processes. */
|
|
35
|
+
status?: string;
|
|
36
|
+
/** Length in milliseconds. */
|
|
37
|
+
duration?: number;
|
|
38
|
+
thumbnailUrl?: string;
|
|
39
|
+
/** The embed URL of a linked (YouTube, Vimeo, …) video. */
|
|
40
|
+
externalUrl?: string;
|
|
41
|
+
externalId?: string;
|
|
42
|
+
}
|
|
43
|
+
/** A selectable image (cover or poster). `selected` is the image URL. */
|
|
44
|
+
export interface WixVideoImage {
|
|
45
|
+
selected?: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** A page of a paginated list. */
|
|
48
|
+
export interface WixVideoPage<T> {
|
|
49
|
+
total?: number;
|
|
50
|
+
cursor?: string | null;
|
|
51
|
+
entities?: T[];
|
|
52
|
+
}
|
|
53
|
+
export interface WixVideo {
|
|
54
|
+
id: string;
|
|
55
|
+
title?: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
publisher?: string;
|
|
58
|
+
/** `COMPUTER` | `GOOGLE_DRIVE` | `DROPBOX` (hosted) | `YOUTUBE` | `VIMEO` | `FACEBOOK` | `LIVE`. */
|
|
59
|
+
source?: string;
|
|
60
|
+
/** `VISIBLE` for a published video. */
|
|
61
|
+
status?: string;
|
|
62
|
+
cover?: WixVideoImage | null;
|
|
63
|
+
poster?: WixVideoImage | null;
|
|
64
|
+
content?: WixVideoMedia | null;
|
|
65
|
+
pricing?: WixVideoPricing[];
|
|
66
|
+
/** The viewer's SALE purchase, when the query asks for it. */
|
|
67
|
+
purchase?: WixVideoPurchase | null;
|
|
68
|
+
/** The viewer's RENT purchase, when the query asks for it (GraphQL alias). */
|
|
69
|
+
rent_purchase?: WixVideoPurchase | null;
|
|
70
|
+
}
|
|
71
|
+
export interface WixVideoChannel {
|
|
72
|
+
id: string;
|
|
73
|
+
title?: string;
|
|
74
|
+
description?: string;
|
|
75
|
+
/** `INTERNAL` | `YOUTUBE`. */
|
|
76
|
+
source?: string;
|
|
77
|
+
featuredVideoId?: string | null;
|
|
78
|
+
hasPaidVideos?: boolean;
|
|
79
|
+
cover?: WixVideoImage | null;
|
|
80
|
+
pricing?: WixVideoPricing[];
|
|
81
|
+
/** The viewer's SUBSCRIPTION purchase, when the query asks for it. */
|
|
82
|
+
purchase?: WixVideoPurchase | null;
|
|
83
|
+
/** The channel's videos: only `total` in a list, a page when the query asks for one. */
|
|
84
|
+
videos?: WixVideoPage<WixVideo>;
|
|
85
|
+
}
|
|
86
|
+
/** A video together with the channel it belongs to. */
|
|
87
|
+
export interface WixVideoInChannel {
|
|
88
|
+
channel: WixVideoChannel;
|
|
89
|
+
video: WixVideo;
|
|
90
|
+
}
|
|
91
|
+
/** Flags every error this client throws carries, so a caller can branch without
|
|
92
|
+
* matching message text. */
|
|
93
|
+
export interface WixVideoErrorFlags {
|
|
94
|
+
/** The gateway refused the viewer (membership, purchase or permission). */
|
|
95
|
+
denied: boolean;
|
|
96
|
+
/** The gateway needs a signed-in member. */
|
|
97
|
+
signInRequired: boolean;
|
|
98
|
+
/** The requested channel does not exist or is not visible. */
|
|
99
|
+
notFound: boolean;
|
|
100
|
+
}
|
|
101
|
+
export type WixVideoError = Error & WixVideoErrorFlags;
|
|
102
|
+
/** Build an error carrying the `WixVideoErrorFlags` (each defaults to false). */
|
|
103
|
+
export declare function wixVideoError(message: string, flags?: Partial<WixVideoErrorFlags>): WixVideoError;
|
|
104
|
+
/** True when a web bridge refused the gateway URL. Wix Video is then out of reach on
|
|
105
|
+
* this surface: the same read works in the native apps. */
|
|
106
|
+
export declare function isWixVideoWebRefusal(error: unknown): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Run one GraphQL read against the Wix Video gateway and return its `data`.
|
|
109
|
+
*
|
|
110
|
+
* The gateway answers HTTP 200 with an `errors` array for a refused or failed query.
|
|
111
|
+
* That is thrown, never returned as empty data: a failed query must not look like a
|
|
112
|
+
* site with no videos.
|
|
113
|
+
*
|
|
114
|
+
* @scope visitor
|
|
115
|
+
*/
|
|
116
|
+
export declare function wixVideoQuery<T>(query: string, variables?: Record<string, unknown>, opts?: WixCallOptions): Promise<T>;
|
|
117
|
+
/** Read every page of a cursor-paginated list. Rows are de-duplicated by id. A
|
|
118
|
+
* repeated or malformed cursor throws instead of looping or returning a partial list. */
|
|
119
|
+
export declare function wixVideoPages<T extends {
|
|
120
|
+
id: string;
|
|
121
|
+
}>(fetchPage: (cursor: string | null) => Promise<WixVideoPage<T> | null | undefined>): Promise<T[]>;
|
|
122
|
+
/** The channel fields a list or card needs. */
|
|
123
|
+
export declare const CHANNEL_FIELDS = "id title description source featuredVideoId hasPaidVideos cover { selected } videos { total }";
|
|
124
|
+
/** The channel fields an access decision needs (`canWatchVideo`). */
|
|
125
|
+
export declare const CHANNEL_ACCESS_FIELDS = "id title pricing { type enabled required } purchase(filter: {type: SUBSCRIPTION}) { status expiresAt }";
|
|
126
|
+
/** The video fields a card needs: title, images, length and processing state. */
|
|
127
|
+
export declare const VIDEO_CARD_FIELDS = "id title source status cover { selected } poster { selected } content { status duration thumbnailUrl externalUrl externalId } pricing { type enabled }";
|
|
128
|
+
/** The video fields playback and an access decision need. */
|
|
129
|
+
export declare 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 }";
|
|
130
|
+
export interface ListChannelsOptions extends WixCallOptions {
|
|
131
|
+
/** Also read the first N videos of each channel (owner's order). 0 (default) reads none. */
|
|
132
|
+
videosPerChannel?: number;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Every channel of the site, in the owner's order (all pages).
|
|
136
|
+
*
|
|
137
|
+
* @scope visitor
|
|
138
|
+
*/
|
|
139
|
+
export declare function listChannels(opts?: ListChannelsOptions): Promise<WixVideoChannel[]>;
|
|
140
|
+
/**
|
|
141
|
+
* One channel and all its videos, in the owner's order. Throws a `notFound` error when
|
|
142
|
+
* the channel does not exist.
|
|
143
|
+
*
|
|
144
|
+
* @scope visitor
|
|
145
|
+
*/
|
|
146
|
+
export declare function listChannelVideos(channelId: string, opts?: WixCallOptions): Promise<{
|
|
147
|
+
channel: WixVideoChannel;
|
|
148
|
+
videos: WixVideo[];
|
|
149
|
+
}>;
|
|
150
|
+
/**
|
|
151
|
+
* One video with its channel's access fields. `null` when the channel does not exist;
|
|
152
|
+
* `video: null` when the channel has no such video.
|
|
153
|
+
*
|
|
154
|
+
* @scope visitor
|
|
155
|
+
*/
|
|
156
|
+
export declare function getVideo(channelId: string, videoId: string, opts?: WixCallOptions): Promise<{
|
|
157
|
+
channel: WixVideoChannel;
|
|
158
|
+
video: WixVideo | null;
|
|
159
|
+
} | null>;
|
|
160
|
+
/**
|
|
161
|
+
* An authorized HLS stream URL for a hosted video (source `COMPUTER`, `GOOGLE_DRIVE`
|
|
162
|
+
* or `DROPBOX`), or "" when the gateway gives none. Check `canWatchVideo` first: the
|
|
163
|
+
* gateway authorizes the stream per viewer. A linked (YouTube, …) video has no stream
|
|
164
|
+
* here; use `youtubeVideoId`.
|
|
165
|
+
*
|
|
166
|
+
* @scope visitor
|
|
167
|
+
*/
|
|
168
|
+
export declare function getVideoStreamUrl(channelId: string, videoId: string, opts?: WixCallOptions): Promise<string>;
|
|
169
|
+
export interface ListLatestVideosOptions extends WixCallOptions {
|
|
170
|
+
/** Most videos to return (default 8). */
|
|
171
|
+
limit?: number;
|
|
172
|
+
/** Channels to read (first page, default 10). */
|
|
173
|
+
channels?: number;
|
|
174
|
+
/** Videos to read from each channel (default 4). */
|
|
175
|
+
perChannel?: number;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The newest ready videos across the site's channels, for a rail or carousel: ONE
|
|
179
|
+
* request that reads the first videos of the first channels. Channel order and each
|
|
180
|
+
* channel's own video order are kept, and the channels take turns, so one large
|
|
181
|
+
* channel cannot fill the whole rail.
|
|
182
|
+
*
|
|
183
|
+
* @scope visitor
|
|
184
|
+
*/
|
|
185
|
+
export declare function listLatestVideos(opts?: ListLatestVideosOptions): Promise<WixVideoInChannel[]>;
|
|
@@ -1345,6 +1345,10 @@ async function getProducts(productIds) {
|
|
|
1345
1345
|
});
|
|
1346
1346
|
return Array.isArray(r?.products) ? r.products : [];
|
|
1347
1347
|
}
|
|
1348
|
+
async function restore() {
|
|
1349
|
+
const r = await dispatch("capability.iap.restore");
|
|
1350
|
+
return Array.isArray(r?.entitlements) ? r.entitlements : [];
|
|
1351
|
+
}
|
|
1348
1352
|
async function purchaseForVerification(input) {
|
|
1349
1353
|
if (!nonempty2(input?.productId) || !isUUID2(input?.appAccountToken)) return failure2("invalidArgument");
|
|
1350
1354
|
const result = await managedDispatch(() => dispatch("capability.iap.purchaseForVerification", input));
|
|
@@ -2526,6 +2530,7 @@ function createIapCommerceWith(deps) {
|
|
|
2526
2530
|
let stopWatchingAccess;
|
|
2527
2531
|
let checkoutStarted = false;
|
|
2528
2532
|
let recheckAfterOpening = false;
|
|
2533
|
+
let restoring;
|
|
2529
2534
|
async function loadPrices(items) {
|
|
2530
2535
|
if (!deps.pricing.enabled) return { scopeComplete: true };
|
|
2531
2536
|
lastPricedAt = deps.clock.now();
|
|
@@ -2557,6 +2562,38 @@ function createIapCommerceWith(deps) {
|
|
|
2557
2562
|
function start() {
|
|
2558
2563
|
return recover((opened) => opened.start());
|
|
2559
2564
|
}
|
|
2565
|
+
function restore2() {
|
|
2566
|
+
return restoring ?? (restoring = restoreOnce().finally(() => {
|
|
2567
|
+
restoring = void 0;
|
|
2568
|
+
}));
|
|
2569
|
+
}
|
|
2570
|
+
async function restoreOnce() {
|
|
2571
|
+
const session = deps.session.current();
|
|
2572
|
+
if (session.kind !== "member") return { status: "needsSignIn" };
|
|
2573
|
+
const before = state().purchase.items;
|
|
2574
|
+
const opened = await startedCheckout();
|
|
2575
|
+
if (deps.session.current().generation !== session.generation) return { status: "failed", code: "sessionChanged" };
|
|
2576
|
+
if (!opened) return { status: "failed", code: "unavailable" };
|
|
2577
|
+
if (!await syncedAppStore()) return { status: "failed", code: "storeUnavailable" };
|
|
2578
|
+
if (deps.session.current().generation !== session.generation) return { status: "failed", code: "sessionChanged" };
|
|
2579
|
+
const purchase = (await recover((opened2) => opened2.retry())).purchase;
|
|
2580
|
+
if (deps.session.current().generation !== session.generation) return { status: "failed", code: "sessionChanged" };
|
|
2581
|
+
const after = purchase.items;
|
|
2582
|
+
const newly = (matches) => Math.max(0, countOf(after, matches) - countOf(before, matches));
|
|
2583
|
+
const result = {
|
|
2584
|
+
status: "restored",
|
|
2585
|
+
recovered: newly(isRecovered),
|
|
2586
|
+
// Held refusals stay in the queue; a final refusal is finished, so only this restore's count.
|
|
2587
|
+
refused: countOf(after, isHeldRefusal) + newly(isFinalRefusal2),
|
|
2588
|
+
pending: countOf(after, isStillPending)
|
|
2589
|
+
};
|
|
2590
|
+
const settled = result.recovered + newly(isFinalRefusal2) > 0;
|
|
2591
|
+
if (purchase.unfinishedCount === null && !settled) return { status: "failed", code: "storeUnavailable" };
|
|
2592
|
+
return result;
|
|
2593
|
+
}
|
|
2594
|
+
function syncedAppStore() {
|
|
2595
|
+
return deps.syncAppStore().then(() => true, () => false);
|
|
2596
|
+
}
|
|
2560
2597
|
async function buy(item) {
|
|
2561
2598
|
if (unanswered2(deps.pricing.view(item.reference))) return state();
|
|
2562
2599
|
const started = await startedCheckout();
|
|
@@ -2687,6 +2724,7 @@ function createIapCommerceWith(deps) {
|
|
|
2687
2724
|
start,
|
|
2688
2725
|
buy,
|
|
2689
2726
|
reconcile: reconcile2,
|
|
2727
|
+
restore: restore2,
|
|
2690
2728
|
tick: () => checkout ? checkout.tick() : Promise.resolve(state()),
|
|
2691
2729
|
pollDirective,
|
|
2692
2730
|
poll,
|
|
@@ -2707,6 +2745,22 @@ var SUSPENDED_AFTER_MS = 2 * PRICE_REFRESH_MS;
|
|
|
2707
2745
|
function unanswered2(view) {
|
|
2708
2746
|
return view.route === "resolving" || view.reason === "mappingUnavailable";
|
|
2709
2747
|
}
|
|
2748
|
+
function isRecovered(item) {
|
|
2749
|
+
return item.completion === "finished" && item.access !== "rejected";
|
|
2750
|
+
}
|
|
2751
|
+
function isFinalRefusal2(item) {
|
|
2752
|
+
return item.completion === "finished" && item.access === "rejected";
|
|
2753
|
+
}
|
|
2754
|
+
function isHeldRefusal(item) {
|
|
2755
|
+
const unfinished = item.completion === "pending" || item.completion === "retryRequired";
|
|
2756
|
+
return unfinished && (item.access === "ownershipConflict" || item.access === "rejected");
|
|
2757
|
+
}
|
|
2758
|
+
function isStillPending(item) {
|
|
2759
|
+
return item.completion !== "finished" && item.completion !== "notFound" && !isHeldRefusal(item);
|
|
2760
|
+
}
|
|
2761
|
+
function countOf(items, matches) {
|
|
2762
|
+
return items.filter(matches).length;
|
|
2763
|
+
}
|
|
2710
2764
|
function hostFor(identity, binding) {
|
|
2711
2765
|
if (binding.himalayaAppId !== identity.appId || binding.bundleId !== identity.bundleId) return null;
|
|
2712
2766
|
return { appId: identity.appId, bundleId: identity.bundleId, siteId: binding.siteId };
|
|
@@ -2725,6 +2779,9 @@ function createIapCommerce(options = {}) {
|
|
|
2725
2779
|
session,
|
|
2726
2780
|
host: hostOfWorker(),
|
|
2727
2781
|
store: appleManagedStore,
|
|
2782
|
+
syncAppStore: async () => {
|
|
2783
|
+
await restore();
|
|
2784
|
+
},
|
|
2728
2785
|
refs: createWorkerOrderRefStore(),
|
|
2729
2786
|
clock: { now: () => Date.now() },
|
|
2730
2787
|
adapters: options.adapters ?? [],
|
|
@@ -1622,6 +1622,10 @@ async function getProducts(productIds) {
|
|
|
1622
1622
|
});
|
|
1623
1623
|
return Array.isArray(r?.products) ? r.products : [];
|
|
1624
1624
|
}
|
|
1625
|
+
async function restore() {
|
|
1626
|
+
const r = await dispatch2("capability.iap.restore");
|
|
1627
|
+
return Array.isArray(r?.entitlements) ? r.entitlements : [];
|
|
1628
|
+
}
|
|
1625
1629
|
async function purchaseForVerification(input) {
|
|
1626
1630
|
if (!nonempty2(input?.productId) || !isUUID2(input?.appAccountToken)) return failure2("invalidArgument");
|
|
1627
1631
|
const result = await managedDispatch(() => dispatch2("capability.iap.purchaseForVerification", input));
|
|
@@ -2797,6 +2801,7 @@ function createIapCommerceWith(deps) {
|
|
|
2797
2801
|
let stopWatchingAccess;
|
|
2798
2802
|
let checkoutStarted = false;
|
|
2799
2803
|
let recheckAfterOpening = false;
|
|
2804
|
+
let restoring;
|
|
2800
2805
|
async function loadPrices(items) {
|
|
2801
2806
|
if (!deps.pricing.enabled) return { scopeComplete: true };
|
|
2802
2807
|
lastPricedAt = deps.clock.now();
|
|
@@ -2828,6 +2833,38 @@ function createIapCommerceWith(deps) {
|
|
|
2828
2833
|
function start() {
|
|
2829
2834
|
return recover((opened) => opened.start());
|
|
2830
2835
|
}
|
|
2836
|
+
function restore2() {
|
|
2837
|
+
return restoring ?? (restoring = restoreOnce().finally(() => {
|
|
2838
|
+
restoring = void 0;
|
|
2839
|
+
}));
|
|
2840
|
+
}
|
|
2841
|
+
async function restoreOnce() {
|
|
2842
|
+
const session = deps.session.current();
|
|
2843
|
+
if (session.kind !== "member") return { status: "needsSignIn" };
|
|
2844
|
+
const before = state().purchase.items;
|
|
2845
|
+
const opened = await startedCheckout();
|
|
2846
|
+
if (deps.session.current().generation !== session.generation) return { status: "failed", code: "sessionChanged" };
|
|
2847
|
+
if (!opened) return { status: "failed", code: "unavailable" };
|
|
2848
|
+
if (!await syncedAppStore()) return { status: "failed", code: "storeUnavailable" };
|
|
2849
|
+
if (deps.session.current().generation !== session.generation) return { status: "failed", code: "sessionChanged" };
|
|
2850
|
+
const purchase = (await recover((opened2) => opened2.retry())).purchase;
|
|
2851
|
+
if (deps.session.current().generation !== session.generation) return { status: "failed", code: "sessionChanged" };
|
|
2852
|
+
const after = purchase.items;
|
|
2853
|
+
const newly = (matches) => Math.max(0, countOf(after, matches) - countOf(before, matches));
|
|
2854
|
+
const result = {
|
|
2855
|
+
status: "restored",
|
|
2856
|
+
recovered: newly(isRecovered),
|
|
2857
|
+
// Held refusals stay in the queue; a final refusal is finished, so only this restore's count.
|
|
2858
|
+
refused: countOf(after, isHeldRefusal) + newly(isFinalRefusal2),
|
|
2859
|
+
pending: countOf(after, isStillPending)
|
|
2860
|
+
};
|
|
2861
|
+
const settled = result.recovered + newly(isFinalRefusal2) > 0;
|
|
2862
|
+
if (purchase.unfinishedCount === null && !settled) return { status: "failed", code: "storeUnavailable" };
|
|
2863
|
+
return result;
|
|
2864
|
+
}
|
|
2865
|
+
function syncedAppStore() {
|
|
2866
|
+
return deps.syncAppStore().then(() => true, () => false);
|
|
2867
|
+
}
|
|
2831
2868
|
async function buy(item) {
|
|
2832
2869
|
if (unanswered2(deps.pricing.view(item.reference))) return state();
|
|
2833
2870
|
const started = await startedCheckout();
|
|
@@ -2958,6 +2995,7 @@ function createIapCommerceWith(deps) {
|
|
|
2958
2995
|
start,
|
|
2959
2996
|
buy,
|
|
2960
2997
|
reconcile: reconcile2,
|
|
2998
|
+
restore: restore2,
|
|
2961
2999
|
tick: () => checkout ? checkout.tick() : Promise.resolve(state()),
|
|
2962
3000
|
pollDirective,
|
|
2963
3001
|
poll,
|
|
@@ -2978,6 +3016,22 @@ var SUSPENDED_AFTER_MS = 2 * PRICE_REFRESH_MS;
|
|
|
2978
3016
|
function unanswered2(view) {
|
|
2979
3017
|
return view.route === "resolving" || view.reason === "mappingUnavailable";
|
|
2980
3018
|
}
|
|
3019
|
+
function isRecovered(item) {
|
|
3020
|
+
return item.completion === "finished" && item.access !== "rejected";
|
|
3021
|
+
}
|
|
3022
|
+
function isFinalRefusal2(item) {
|
|
3023
|
+
return item.completion === "finished" && item.access === "rejected";
|
|
3024
|
+
}
|
|
3025
|
+
function isHeldRefusal(item) {
|
|
3026
|
+
const unfinished = item.completion === "pending" || item.completion === "retryRequired";
|
|
3027
|
+
return unfinished && (item.access === "ownershipConflict" || item.access === "rejected");
|
|
3028
|
+
}
|
|
3029
|
+
function isStillPending(item) {
|
|
3030
|
+
return item.completion !== "finished" && item.completion !== "notFound" && !isHeldRefusal(item);
|
|
3031
|
+
}
|
|
3032
|
+
function countOf(items, matches) {
|
|
3033
|
+
return items.filter(matches).length;
|
|
3034
|
+
}
|
|
2981
3035
|
function hostFor(identity, binding) {
|
|
2982
3036
|
if (binding.himalayaAppId !== identity.appId || binding.bundleId !== identity.bundleId) return null;
|
|
2983
3037
|
return { appId: identity.appId, bundleId: identity.bundleId, siteId: binding.siteId };
|
|
@@ -2996,6 +3050,9 @@ function createIapCommerce(options = {}) {
|
|
|
2996
3050
|
session,
|
|
2997
3051
|
host: hostOfWorker(),
|
|
2998
3052
|
store: appleManagedStore,
|
|
3053
|
+
syncAppStore: async () => {
|
|
3054
|
+
await restore();
|
|
3055
|
+
},
|
|
2999
3056
|
refs: createWorkerOrderRefStore(),
|
|
3000
3057
|
clock: { now: () => Date.now() },
|
|
3001
3058
|
adapters: options.adapters ?? [],
|