@moviie/player-expo 0.4.0 → 0.5.1

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/README.md CHANGED
@@ -1,24 +1,48 @@
1
1
  # @moviie/player-expo
2
2
 
3
- React Native / Expo bindings for the Moviie video platform. Re-exports [`@moviie/player-sdk`](https://www.npmjs.com/package/@moviie/player-sdk) and ships `expo-video` integrations (`MoviieVideo`, hooks, telemetry wiring, optional Chromecast adapter).
3
+ React Native / Expo player for the [Moviie](https://moviie.ai) platform. Wraps `expo-video` with the Moviie playback API, custom chrome, telemetry, PiP, background audio, and optional Chromecast.
4
4
 
5
- ## Quickstart (3 steps)
5
+ Full documentation: [docs.moviie.ai/player-expo](https://docs.moviie.ai/player-expo)
6
+
7
+ ## Prerequisites
8
+
9
+ You need a **[Moviie](https://moviie.ai) account** and a **publishable API key** (`mvi_pub_*`).
10
+
11
+ 1. Create an account at [app.moviie.ai/signin](https://app.moviie.ai/signin).
12
+ 2. Go to **Organization Settings → API Keys** and create a **Publishable** key.
13
+ 3. Copy the key — it starts with `mvi_pub_`.
14
+
15
+ Set it as an environment variable in your project:
16
+
17
+ ```bash
18
+ # .env.local
19
+ EXPO_PUBLIC_MOVIIE_PUBLISHABLE_KEY=mvi_pub_your_key_here
20
+ ```
21
+
22
+ > **Never** use a secret key (`mvi_priv_*`) in a client app. The playback API rejects it.
23
+
24
+ ## Install
6
25
 
7
26
  ```bash
8
- # 1. Install (5 mandatory deps)
9
27
  pnpm add @moviie/player-expo \
10
- expo expo-video expo-application expo-screen-orientation \
28
+ expo expo-video expo-application \
11
29
  react-native-svg react-native-reanimated react-native-gesture-handler \
12
30
  react-native-safe-area-context
13
-
14
- # Optional — gain extra features:
15
- # pnpm add expo-secure-store # persistent resume position + viewer token
16
- # pnpm add expo-status-bar # hide status bar in custom fullscreen
17
- # pnpm add react-native-google-cast # Chromecast support (subpath /cast)
18
31
  ```
19
32
 
33
+ Optional extras:
34
+
35
+ | Package | Unlocks |
36
+ |---------|---------|
37
+ | `expo-secure-store` | Persistent viewer token + resume position across sessions |
38
+ | `expo-status-bar` | Hide status bar in custom fullscreen overlay |
39
+ | `react-native-google-cast` | Chromecast button — install only if you need it |
40
+
41
+ ## Setup
42
+
43
+ **1. Add the config plugin** to `app.json`:
44
+
20
45
  ```json
21
- // 2. app.json — add config plugin
22
46
  {
23
47
  "expo": {
24
48
  "plugins": [
@@ -29,8 +53,16 @@ pnpm add @moviie/player-expo \
29
53
  }
30
54
  ```
31
55
 
56
+ **2. Rebuild native projects** after adding or changing plugins:
57
+
58
+ ```bash
59
+ pnpm expo prebuild
60
+ pnpm expo run:ios # or run:android
61
+ ```
62
+
63
+ **3. Wrap your app** with `MoviieProvider`:
64
+
32
65
  ```tsx
33
- // 3. App.tsx
34
66
  import { MoviieProvider, MoviieVideo, useMoviiePlayer } from "@moviie/player-expo"
35
67
 
36
68
  function Player({ embedId }: { embedId: string }) {
@@ -47,184 +79,180 @@ export default function App() {
47
79
  }
48
80
  ```
49
81
 
50
- Run `pnpm expo prebuild && pnpm expo run:ios` (or `run:android`) to compile the
51
- native module — `expo-video` doesn't ship with Expo Go.
82
+ Set `EXPO_PUBLIC_MOVIIE_PUBLISHABLE_KEY` to a `mvi_pub_*` key from your organization settings.
52
83
 
53
- ### Optional dependencies (graceful degradation)
84
+ ---
54
85
 
55
- | Package | Without it |
56
- |---------|------------|
57
- | `expo-secure-store` | Viewer token stays in memory (lost on app kill); resume position **does not persist** between sessions |
58
- | `expo-status-bar` | Status bar stays visible during custom fullscreen overlay |
59
- | `react-native-google-cast` | Chromecast button doesn't appear; player works normally |
86
+ ## API reference
60
87
 
61
- When a feature requiring an optional package is exercised without that package
62
- installed, the SDK emits a **single `console.warn`** per session pointing to the
63
- install command. No crash, no hidden errors.
88
+ ### `<MoviieProvider>`
64
89
 
65
- ### API endpoint override (dev only)
90
+ Provides the Moviie client to the component tree. Place it at the root of your app.
66
91
 
67
- For local development against a non-prod backend, set env vars in `.env.local`
68
- (Metro inlines any `EXPO_PUBLIC_*` at build time — no `expo-constants` needed):
92
+ | Prop | Type | Required | Description |
93
+ |------|------|:--------:|-------------|
94
+ | `publishableKey` | `string` | ✓ | Publishable key (`mvi_pub_*`) from your [Moviie](https://moviie.ai) organization settings. |
95
+ | `children` | `ReactNode` | ✓ | Your app tree. |
69
96
 
70
- ```bash
71
- EXPO_PUBLIC_MOVIIE_API_BASE_URL=http://localhost:3000/api/v1
72
- EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL=http://localhost:3000/telemetry/v1
73
- ```
97
+ ---
74
98
 
75
- Overrides only apply when `__DEV__ === true`. Production builds always use the
76
- default `https://api.moviie.ai/v1`.
99
+ ### `useMoviiePlayer(options)`
77
100
 
78
- Full docs: [docs.moviie.ai/player-expo](https://docs.moviie.ai/player-expo) ·
79
- FAQ: [docs.moviie.ai/player-expo/faq](https://docs.moviie.ai/player-expo/faq) ·
80
- Migration: [docs.moviie.ai/player-expo/migration](https://docs.moviie.ai/player-expo/migration)
101
+ Fetches playback metadata and wires native player state. Spread the return value onto `<MoviieVideo>`.
81
102
 
82
- ---
103
+ **Options:**
83
104
 
84
- ## Requirements
105
+ | Option | Type | Default | Description |
106
+ |--------|------|---------|-------------|
107
+ | `embedId` | `string` | — | **Required.** UUID of the embed from the [Moviie](https://moviie.ai) dashboard. |
108
+ | `autoplay` | `boolean` | dashboard | Override the embed's autoplay setting. |
109
+ | `pictureInPicture` | `boolean` | dashboard | Override the embed's PiP setting. |
110
+ | `pictureInPictureAutoStart` | `boolean` | `false` | Automatically enter PiP when the app moves to the background. |
111
+ | `backgroundPlayback` | `boolean` | `false` | Keep audio playing when the app is backgrounded. |
112
+ | `lockScreenNowPlaying` | `boolean` | `false` | Show a Now Playing notification on the lock screen. |
113
+ | `rememberPosition` | `boolean` | dashboard | Override the embed's "remember position" setting. |
85
114
 
86
- - Expo SDK 52+
87
- - `expo-video` 2+
88
- - Dev client recommended (`expo-video` does not run in Expo Go)
89
- - **Publishable API key** (`mvi_pub_*`) for `MoviieClient.getPlayback` — set `EXPO_PUBLIC_MOVIIE_PUBLISHABLE_KEY` (or equivalent) before fetching playback
115
+ **Returns:**
90
116
 
91
- ## App config
117
+ | Field | Type | Description |
118
+ |-------|------|-------------|
119
+ | `player` | `VideoPlayer \| null` | `expo-video` player instance. `null` on web. |
120
+ | `playback` | `MoviiePlaybackData \| null` | Full playback metadata from the API. `null` while loading. |
121
+ | `error` | `Error \| null` | Typed error (see Error codes). `null` when healthy. |
122
+ | `isLoading` | `boolean` | `true` while the first playback fetch is in-flight. |
123
+ | `videoPresentation` | `MoviieVideoPresentationProps` | PiP and linear playback flags, pre-computed from playback + options. Spread onto `<MoviieVideo>`. |
124
+ | `retry` | `() => void` | Re-triggers the playback fetch. |
92
125
 
93
- Register **`@moviie/player-expo`** so native manifests receive background audio and PiP-related defaults. Pair it with the **`expo-video`** plugin toggles from the [Expo Video docs](https://docs.expo.dev/versions/latest/sdk/video/). After changing plugin options, run **`expo prebuild`** (or trigger an EAS native build) so **Info.plist** and **AndroidManifest.xml** pick up the updates.
126
+ ---
94
127
 
95
- ```json
96
- {
97
- "expo": {
98
- "plugins": [
99
- [
100
- "@moviie/player-expo",
101
- {
102
- "backgroundPlayback": true,
103
- "pictureInPicture": true
104
- }
105
- ],
106
- [
107
- "expo-video",
108
- {
109
- "supportsBackgroundPlayback": true,
110
- "supportsPictureInPicture": true
111
- }
112
- ]
113
- ]
114
- }
115
- }
116
- ```
128
+ ### `<MoviieVideo>`
129
+
130
+ Main playback component. Accepts the full return value of `useMoviiePlayer` spread as props, plus presentation and behaviour overrides.
131
+
132
+ | Prop | Type | Default | Description |
133
+ |------|------|---------|-------------|
134
+ | `player` | `VideoPlayer \| null` | — | Player instance from `useMoviiePlayer`. |
135
+ | `playback` | `MoviiePlaybackData \| null` | — | Playback metadata from `useMoviiePlayer`. |
136
+ | `aspectRatio` | `number` | — | Width ÷ height ratio (e.g. `16 / 9`). |
137
+ | `native` | `boolean` | `false` | Use the platform's native `VideoView` chrome instead of the Moviie custom skin. |
138
+ | `nativeControls` | `boolean` | auto | Show or hide native `VideoView` controls (only relevant when `native={true}`). |
139
+ | `pictureInPicture` | `boolean` | hook / dashboard | Override PiP availability for this component. |
140
+ | `pictureInPictureAutoStart` | `boolean` | `false` | Auto-enter PiP when the app moves to the background. |
141
+ | `controlsAutoHideMs` | `number` | `3000` | Milliseconds of inactivity before the Moviie chrome hides. |
142
+ | `controlsVisibleByDefault` | `boolean` | `false` | Show the chrome immediately on mount without a tap. |
143
+ | `castAdapter` | `MoviieCastAdapter \| null` | — | Chromecast adapter. Create with `createGoogleCastAdapter()` from `@moviie/player-expo/cast`. |
144
+ | `cast` | `boolean` | dashboard | Override the embed's Chromecast setting. `false` hides the button and silences the missing-adapter warning. |
145
+ | `isLoading` | `boolean` | — | From `useMoviiePlayer`. Shows a loading state in the chrome. |
146
+ | `error` | `Error \| null` | — | From `useMoviiePlayer`. Triggers the built-in error shell. |
147
+ | `retry` | `() => void` | — | From `useMoviiePlayer`. Called by the built-in retry button. |
148
+ | `onRetry` | `() => void` | — | Replace the default retry behaviour. You must call `moviie.retry()` yourself if needed. |
149
+
150
+ Also accepts all `VideoViewProps` from `expo-video` (except `player`, which is managed internally).
117
151
 
118
- **Plugin options:**
152
+ ---
119
153
 
120
- - **`backgroundPlayback`**: iOS `UIBackgroundModes` → `audio`
121
- - **`pictureInPicture`**: iOS adds `picture-in-picture` plus `audio`; Android main activity `supportsPictureInPicture` + `resizeableActivity`
154
+ ### `<MoviieErrorBoundary>`
122
155
 
123
- API endpoint overrides são **dev only** via env vars `EXPO_PUBLIC_MOVIIE_API_BASE_URL` / `EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL` (não expostos no plugin).
156
+ React error boundary that catches crashes inside `<MoviieVideo>` and prevents them from bubbling up to your app.
124
157
 
125
- ## Usage
158
+ | Prop | Type | Default | Description |
159
+ |------|------|---------|-------------|
160
+ | `children` | `ReactNode` | — | Component tree to protect — wrap `<MoviieVideo>` here. |
161
+ | `fallback` | `({ error: Error, reset: () => void }) => ReactNode` | built-in shell | Custom fallback UI rendered when a crash occurs. `reset()` unmounts and remounts the player. |
162
+ | `onError` | `(error: Error, info: React.ErrorInfo) => void` | — | Called on each caught error. Pass `Sentry.captureException` directly. |
126
163
 
127
- See the internal playground app `apps/playground-expo` and product docs at [docs.moviie.ai](https://docs.moviie.ai).
164
+ ```tsx
165
+ import { MoviieErrorBoundary, MoviieVideo, useMoviiePlayer } from "@moviie/player-expo"
166
+ import * as Sentry from "@sentry/react-native"
128
167
 
129
- Import the SDK (re-exported from `@moviie/player-sdk`) and Expo bindings from this package:
168
+ const moviie = useMoviiePlayer({ embedId })
130
169
 
131
- ```typescript
132
- import { MoviieClient, MOVIIE_PLAYER_EXPO_PKG_VERSION } from "@moviie/player-expo"
170
+ <MoviieErrorBoundary
171
+ onError={(err, info) => Sentry.captureException(err, { contexts: { react: info } })}
172
+ fallback={({ error, reset }) => <MyFallback message={error.message} onRetry={reset} />}
173
+ >
174
+ <MoviieVideo {...moviie} aspectRatio={16 / 9} />
175
+ </MoviieErrorBoundary>
133
176
  ```
134
177
 
135
- ### Fim da reprodução (`ended`)
136
-
137
- O expo-video emite `playToEnd` quando o vídeo termina naturalmente. Este pacote alinha isso a `PLAYER_API_EVENTS.ENDED`.
178
+ ---
138
179
 
139
- **React hook dedicado:**
180
+ ## Error codes
140
181
 
141
- ```typescript
142
- import { useMoviiePlaybackEnded } from "@moviie/player-expo"
182
+ Each error from `useMoviiePlayer` has a `.code` field and maps to a typed class from `@moviie/player-sdk`.
143
183
 
144
- useMoviiePlaybackEnded(player, () => {
145
- // vídeo chegou ao fim
146
- })
147
- ```
184
+ | Code | Class | Cause | Default CTA |
185
+ |------|-------|-------|-------------|
186
+ | `auth` | `MoviieAuthError` | Invalid or missing publishable key. | Open dashboard |
187
+ | `not_found` | `MoviieNotFoundError` | Embed ID does not exist or was deleted. | Open dashboard |
188
+ | `bundle_blocked` | `MoviieBundleBlockedError` | App bundle ID not in the embed's allowlist. Most common on mobile. | Open dashboard |
189
+ | `referrer_blocked` | `MoviieReferrerBlockedError` | Request origin not in the embed's referrer allowlist. | Open dashboard |
190
+ | `subscription_inactive` | `MoviieSubscriptionInactiveError` | Organization subscription is paused or expired. | Open dashboard |
191
+ | `network` | `MoviieNetworkError` | Network request failed (timeout, unreachable). High frequency on mobile. | Retry |
192
+ | `rate_limit` | `MoviieRateLimitError` | Too many requests in a short period. | Retry |
193
+ | `unknown` | `Error` | Unrecognized error. | Retry |
148
194
 
149
- **React evento genérico:**
195
+ Detect by instance or code string:
150
196
 
151
- ```typescript
152
- import { PLAYER_API_EVENTS, useMoviieEvent } from "@moviie/player-expo"
197
+ ```tsx
198
+ import { MoviieBundleBlockedError } from "@moviie/player-sdk"
153
199
 
154
- useMoviieEvent(player, PLAYER_API_EVENTS.ENDED, () => {
155
- // vídeo chegou ao fim
156
- })
200
+ if (error instanceof MoviieBundleBlockedError) { /* fix allowlist */ }
201
+ if (error?.code === "network") { /* retry */ }
157
202
  ```
158
203
 
159
- **Fora de React — subscription:**
204
+ ---
160
205
 
161
- ```typescript
162
- import { addMoviiePlaybackEndedListener } from "@moviie/player-expo"
206
+ ## Chromecast (optional)
163
207
 
164
- const sub = addMoviiePlaybackEndedListener(player, () => {
165
- // vídeo chegou ao fim
166
- })
208
+ Cast support lives in the `@moviie/player-expo/cast` subpath. Install only if you need it:
167
209
 
168
- sub.remove()
210
+ ```bash
211
+ pnpm add react-native-google-cast
169
212
  ```
170
213
 
171
- **UI derivada de estado (ex.: ícone “repetir” no centro):** use `computeMoviiePlaybackEnded` com `playing`, `currentTime`, `duration`, `isLive` e `loop` — a mesma heurística usada pela skin Moviie, com `MOVIIE_SKIN_TIMELINE_END_SNAP_EPSILON_SECONDS` disponível no pacote se precisar espelhar o snap ao fim da timeline.
214
+ Add the plugin to `app.json`, then rebuild:
172
215
 
173
- ### Resilience: error boundary
216
+ ```json
217
+ ["react-native-google-cast", { "iosReceiverAppId": "CC1AD845", "androidReceiverAppId": "CC1AD845" }]
218
+ ```
174
219
 
175
- Wrap `MoviieVideo` in `MoviieErrorBoundary` to isolate crashes (bug in
176
- `expo-video`, missing native module, etc.) from the rest of your app:
220
+ Wire the adapter:
177
221
 
178
222
  ```tsx
179
- import * as Sentry from "@sentry/react-native"
180
- import { MoviieErrorBoundary, MoviieVideo } from "@moviie/player-expo"
223
+ import { useMemo } from "react"
224
+ import { createGoogleCastAdapter } from "@moviie/player-expo/cast"
181
225
 
182
- <MoviieErrorBoundary
183
- onError={(err, info) => Sentry.captureException(err, { contexts: { react: info } })}
184
- fallback={({ error, reset }) => <YourFallback message={error.message} onRetry={reset} />}
185
- >
186
- <MoviieVideo {...moviie} />
187
- </MoviieErrorBoundary>
226
+ const castAdapter = useMemo(() => createGoogleCastAdapter(), [])
227
+ <MoviieVideo {...moviie} castAdapter={castAdapter} aspectRatio={16 / 9} />
188
228
  ```
189
229
 
190
- ### Telemetry hooks (Sentry / PostHog / Datadog)
191
-
192
- `@moviie/player-expo` ships its own telemetry to the Moviie backend. To **also**
193
- mirror events into your monitoring pipeline, pass the opt-in callbacks:
230
+ Without a `castAdapter`, the cast button is hidden and the player works normally.
194
231
 
195
- ```tsx
196
- <MoviieVideo
197
- {...moviie}
198
- onTelemetryError={(error, ctx) =>
199
- Sentry.captureException(error, { tags: { embedId: ctx.embedId, phase: ctx.phase } })
200
- }
201
- onTelemetryEvent={(event) => posthog.capture(`moviie.${event.name}`, event)}
202
- />
203
- ```
204
-
205
- Exceptions thrown by the callbacks are swallowed and logged — they never crash
206
- the player. No PII flows through these hooks.
232
+ ---
207
233
 
208
- ### Cast (Chromecast, optional)
234
+ ## End of playback
209
235
 
210
- Cast support is provided via the optional subpath `@moviie/player-expo/cast`. Add
211
- the peer dependency and wire the adapter:
236
+ ```tsx
237
+ import { useMoviiePlaybackEnded } from "@moviie/player-expo"
212
238
 
213
- ```bash
214
- pnpm add react-native-google-cast
239
+ useMoviiePlaybackEnded(player, () => {
240
+ // video reached the end
241
+ })
215
242
  ```
216
243
 
217
- ```tsx
218
- import { createGoogleCastAdapter } from "@moviie/player-expo/cast"
244
+ Or use `PLAYER_API_EVENTS.ENDED` with `useMoviieEvent` for a generic handler.
219
245
 
220
- const castAdapter = useMemo(() => createGoogleCastAdapter(), [])
246
+ ---
221
247
 
222
- <MoviieVideo {...moviie} castAdapter={castAdapter} />
223
- ```
248
+ ## Requirements
224
249
 
225
- If you don't use cast, **don't install `react-native-google-cast`** the package
226
- never imports it from the main entry, so your bundle stays slim.
250
+ - Expo SDK 52+
251
+ - `expo-video` 2+
252
+ - Dev client required — `expo-video` does not work in Expo Go
253
+
254
+ ---
227
255
 
228
256
  ## License
229
257
 
230
- MIT — see [`LICENSE`](./LICENSE). Copyright (c) 2026 Moviie.
258
+ MIT — see [`LICENSE`](./LICENSE). Copyright (c) 2026 [Moviie](https://moviie.ai).
@@ -5,7 +5,7 @@ import * as Application from 'expo-application';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
 
7
7
  // src/constants.ts
8
- var MOVIIE_PLAYER_EXPO_PKG_VERSION = "0.4.0";
8
+ var MOVIIE_PLAYER_EXPO_PKG_VERSION = "0.5.1";
9
9
  var MOVIIE_PLAYBACK_MEMORY_CACHE_TTL_MS = 5 * 60 * 1e3;
10
10
  var MOVIIE_PLAYBACK_PROFILE = {
11
11
  VSL: "vsl",
@@ -290,5 +290,5 @@ function MoviieProvider({
290
290
  }
291
291
 
292
292
  export { EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV, EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV, EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN_ENV, MOVIIE_BRANDING_MARKETING_ORIGIN, MOVIIE_BRANDING_UTM_PARAM_CAMPAIGN, MOVIIE_BRANDING_UTM_PARAM_MEDIUM, MOVIIE_BRANDING_UTM_PARAM_SOURCE, MOVIIE_EMBED_BRAND_LETTERMARK_STROKE_WIDTH, MOVIIE_EMBED_BRAND_UTM, MOVIIE_EMBED_BRAND_VIEW_BOX, MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE, MOVIIE_PLAYBACK_MEMORY_CACHE_TTL_MS, MOVIIE_PLAYBACK_PROFILE, MOVIIE_PLAYER_EXPO_EMBED_JS_MARKER_ATTR, MOVIIE_PLAYER_EXPO_PKG_VERSION, MOVIIE_REMEMBER_POSITION_DEBOUNCE_MS, MOVIIE_REMEMBER_POSITION_STORAGE_PREFIX, MOVIIE_SKIN_BRAND_MARK_ARTBOARD_HEIGHT_PX, MOVIIE_SKIN_BRAND_MARK_ARTBOARD_WIDTH_PX, MOVIIE_SKIN_BRAND_MARK_TARGET_WIDTH_AT_REFERENCE_PT, MOVIIE_SKIN_BUFFERING_INDICATOR_SLOT_PX, MOVIIE_SKIN_BUFFER_UNDERRUN_LEAD_SECONDS, MOVIIE_SKIN_CENTER_CLUSTER_COLUMN_GAP_PX, MOVIIE_SKIN_CENTER_PLAY_ICON_PX, MOVIIE_SKIN_CENTER_PLAY_SCRIM_DIAMETER_AT_REFERENCE_PT, MOVIIE_SKIN_CENTER_SEEK_SCRIM_DIAMETER_AT_REFERENCE_PT, MOVIIE_SKIN_CHROME_CONTROL_PRESSED_OPACITY, MOVIIE_SKIN_CHROME_CONTROL_REST_OPACITY, MOVIIE_SKIN_CHROME_EDGE_GRADIENT_EDGE_SOLID_FADE_END_FRACTION, MOVIIE_SKIN_CHROME_EDGE_GRADIENT_HEIGHT_AT_REFERENCE_PT, MOVIIE_SKIN_CHROME_EDGE_GRADIENT_MIN_CLEAR_MIDDLE_PX, MOVIIE_SKIN_CHROME_FOREGROUND_HEX, MOVIIE_SKIN_CHROME_GRADIENT_BLACK_HEX, MOVIIE_SKIN_CHROME_GRADIENT_EDGE_ALPHA, MOVIIE_SKIN_CHROME_SCRIM_BLACK_RGBA, MOVIIE_SKIN_CHROME_SVG_GRADIENT_BOTTOM_EDGE_ID, MOVIIE_SKIN_CHROME_SVG_GRADIENT_TOP_EDGE_ID, MOVIIE_SKIN_CLOCK_TEXT_FONT_SIZE_AT_REFERENCE_PT, MOVIIE_SKIN_CONTROLS_AUTO_HIDE_MS, MOVIIE_SKIN_CONTROLS_FADE_MS, MOVIIE_SKIN_CONTROL_ICON_PX, MOVIIE_SKIN_CUSTOM_FULLSCREEN_ENTER_SCALE_START, MOVIIE_SKIN_CUSTOM_FULLSCREEN_HUD_EDGE_BOOST_REFERENCE_PT, MOVIIE_SKIN_CUSTOM_FULLSCREEN_ROTATE_Z_DEGREES, MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_BACKGROUND_HEX, MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_OVERSCAN_PX, MOVIIE_SKIN_CUSTOM_FULLSCREEN_TRANSITION_MS, MOVIIE_SKIN_CUSTOM_FULLSCREEN_VIDEO_CONTENT_FIT, MOVIIE_SKIN_DEFAULT_ACCENT_HEX, MOVIIE_SKIN_FLOATING_FULLSCREEN_ICON_AT_REFERENCE_PT, MOVIIE_SKIN_FLOATING_FULLSCREEN_SCRIM_DIAMETER_AT_REFERENCE_PT, MOVIIE_SKIN_FLOATING_FULLSCREEN_TOP_ICON_AT_REFERENCE_PT, MOVIIE_SKIN_FLOATING_HUD_ABOVE_TIMELINE_GAP_AT_REFERENCE_PT, MOVIIE_SKIN_FLOATING_HUD_BUTTON_GAP_AT_REFERENCE_PT, MOVIIE_SKIN_FLOATING_HUD_CLOCK_CORNER_RADIUS_PX, MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX, MOVIIE_SKIN_FLOATING_HUD_TRAILING_HIT_SLOP_PX, MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT, MOVIIE_SKIN_LAYOUT_SCALE_MAX, MOVIIE_SKIN_LAYOUT_SCALE_MIN, MOVIIE_SKIN_SEEK_ICON_PX, MOVIIE_SKIN_SEEK_JUMP_SECONDS, MOVIIE_SKIN_TIMELINE_BAR_HEIGHT_PX, MOVIIE_SKIN_TIMELINE_BUFFER_LAYER_RGBA, MOVIIE_SKIN_TIMELINE_CHAPTER_SNAP_THRESHOLD_SECONDS, MOVIIE_SKIN_TIMELINE_END_SNAP_EPSILON_SECONDS, MOVIIE_SKIN_TIMELINE_RAIL_BACKGROUND_RGBA, MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_BOTTOM_DP, MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_HORIZONTAL_DP, MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_TOP_DP, MOVIIE_SKIN_TIMELINE_THUMB_BORDER_RGBA, MOVIIE_SKIN_TIMELINE_THUMB_DIAMETER_PX, MOVIIE_SKIN_TIMELINE_THUMB_DRAG_DIAMETER_MULTIPLIER, MOVIIE_SKIN_TIMELINE_TOUCH_EXPANSION_VERTICAL_DP, MOVIIE_SKIN_TIMELINE_TOUCH_PADDING_VERTICAL_PX, MOVIIE_SKIN_TOP_ICON_CAST_VISUAL_SCALE, MOVIIE_SKIN_TOP_ICON_FULLSCREEN_VISUAL_SCALE, MOVIIE_SKIN_TOP_ICON_PIP_VISUAL_SCALE, MOVIIE_SKIN_VOLUME_LOW_ICON_THRESHOLD, MOVIIE_SMART_PROGRESS_BAR_HEIGHT_DP, MOVIIE_SMART_PROGRESS_CONFIG, MOVIIE_SMART_PROGRESS_FILL_TRANSITION_MS, MOVIIE_SMART_PROGRESS_Z_INDEX, MOVIIE_VIDEO_DEFAULT_CONTENT_FIT, MOVIIE_VIEWER_TOKEN_SECURE_STORE_KEY, MOVIIE_WATCH_EMBED_JS_PATH, MOVIIE_WATCH_ORIGIN_DEFAULT, MoviieProvider, SecureStoreViewerTokenStore, useMoviieContext, warnOnce };
293
- //# sourceMappingURL=chunk-67DJ7NOB.mjs.map
294
- //# sourceMappingURL=chunk-67DJ7NOB.mjs.map
293
+ //# sourceMappingURL=chunk-5P3BQYRP.mjs.map
294
+ //# sourceMappingURL=chunk-5P3BQYRP.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/apply-expo-moviie-endpoints.ts","../src/lib/warn-once.ts","../src/secure-store-viewer-token-store.ts","../src/platform/native-application-id.ts","../src/platform/platform-client-info.ts","../src/provider/moviie-provider.tsx"],"names":["MemoryViewerTokenStore"],"mappings":"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","file":"chunk-67DJ7NOB.mjs","sourcesContent":["export const MOVIIE_PLAYER_EXPO_PKG_VERSION = '0.4.0' as const\n\nexport const MOVIIE_PLAYBACK_MEMORY_CACHE_TTL_MS = 5 * 60 * 1000\n\n/** Playback profile strings returned by the playback API (aligned with web embed). */\nexport const MOVIIE_PLAYBACK_PROFILE = {\n VSL: 'vsl',\n CUSTOM: 'custom',\n} as const\n\n/**\n * Smart Progress curve — mirrors {@link SMART_PROGRESS_CONFIG} on the web embed\n * (`apps/web/src/app/embed/[id]/constants.ts`).\n */\nexport const MOVIIE_SMART_PROGRESS_CONFIG = {\n R1: 0.18,\n P1: 0.62,\n R2: 0.8,\n P2: 0.95,\n P_MAX_BEFORE_END: 0.99,\n} as const\n\n/** Fill animation duration (ms); aligns with web `.moviie-smart-progress-fill` transition. */\nexport const MOVIIE_SMART_PROGRESS_FILL_TRANSITION_MS = 150 as const\n\n/** Absolute bottom bar height (dp) for native Smart Progress strip. */\nexport const MOVIIE_SMART_PROGRESS_BAR_HEIGHT_DP = 12 as const\n\nexport const MOVIIE_SMART_PROGRESS_Z_INDEX = 34 as const\n\n/**\n * SecureStore key prefix for resume position (`{prefix}{embedId}`).\n * Embed IDs are UUIDs from the API.\n */\nexport const MOVIIE_REMEMBER_POSITION_STORAGE_PREFIX = 'moviie.resume_position.' as const\n\n/** Debounce interval before persisting resume position while playing. */\nexport const MOVIIE_REMEMBER_POSITION_DEBOUNCE_MS = 5000 as const\n\n/** Matches embed/web framing defaults when `contentFit` is omitted on `MoviieVideo`. */\nexport const MOVIIE_VIDEO_DEFAULT_CONTENT_FIT = {\n VERTICAL: 'contain',\n HORIZONTAL: 'cover',\n} as const\n\nexport const MOVIIE_BRANDING_MARKETING_ORIGIN = 'https://moviie.ai' as const\n\n/** Origin público da página watch/embed (sem barra final). Override: `EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN`. */\nexport const MOVIIE_WATCH_ORIGIN_DEFAULT = 'https://watch.moviie.ai' as const\n\n/**\n * Variável `EXPO_PUBLIC_*` para override do origin watch/embed em Expo Web (`resolveMoviieWatchOrigin`).\n */\nexport const EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN_ENV = 'EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN' as const\n\n/** Path público do script da API JS do embed (relativo ao watch origin). */\nexport const MOVIIE_WATCH_EMBED_JS_PATH = '/embed.js' as const\n\n/**\n * Atributo único no `<script>` injectado em Expo Web para evitar duplicar `embed.js`\n * quando há vários `MoviieVideo` montados.\n */\nexport const MOVIIE_PLAYER_EXPO_EMBED_JS_MARKER_ATTR = 'data-moviie-player-expo-embed-js' as const\n\n/**\n * Variável `EXPO_PUBLIC_*` que override a base da API Moviie em **dev only**.\n * O Metro inlina qualquer `EXPO_PUBLIC_*` em build time, sem precisar de\n * `expo-constants`. Em produção o SDK usa sempre o default `https://api.moviie.ai/v1`.\n *\n * Exemplo `.env.local`:\n * EXPO_PUBLIC_MOVIIE_API_BASE_URL=http://localhost:3000/api/v1\n */\nexport const EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV = 'EXPO_PUBLIC_MOVIIE_API_BASE_URL' as const\n\n/**\n * Variável `EXPO_PUBLIC_*` que override a base de telemetria em **dev only**.\n * Caso omitida, deriva-se de `{origin}/telemetry/v1` a partir de `apiBaseUrl`.\n */\nexport const EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV = 'EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL' as const\n\nexport const MOVIIE_BRANDING_UTM_PARAM_SOURCE = 'utm_source' as const\nexport const MOVIIE_BRANDING_UTM_PARAM_MEDIUM = 'utm_medium' as const\nexport const MOVIIE_BRANDING_UTM_PARAM_CAMPAIGN = 'utm_campaign' as const\n\nexport const MOVIIE_BRANDING_UTM_SOURCE_VALUE = 'player-expo' as const\nexport const MOVIIE_BRANDING_UTM_MEDIUM_VALUE = 'branding' as const\n\n/** Espelha `PLAYER_EMBED_BRAND_UTM` do embed web (`apps/web/src/app/embed/[id]/constants.ts`). */\nexport const MOVIIE_EMBED_BRAND_UTM = {\n SOURCE: 'moviie_embed_player',\n MEDIUM: 'video_control_bar',\n CAMPAIGN: 'logo_click',\n} as const\n\nexport const MOVIIE_SKIN_DEFAULT_ACCENT_HEX = '#6366f1' as const\n\n/**\n * Valor legado para a prop `controlsAutoHideMs` / `autoHideMs`: o chrome da skin Moviie já não\n * usa temporizador para ocultar — só ao toque fora ou ações (play, seek).\n */\nexport const MOVIIE_SKIN_CONTROLS_AUTO_HIDE_MS = 3000 as const\n\nexport const MOVIIE_SKIN_CONTROLS_FADE_MS = 240 as const\n\nexport const MOVIIE_SKIN_WATERMARK_OPACITY = 0.7 as const\n\nexport const MOVIIE_SKIN_CONTROL_ICON_PX = 22 as const\n\n/**\n * Largura lógica de referência do layout da skin (ex.: frame Figma / iPhone ~390pt).\n * Dimensões em `MOVIIE_SKIN_*_AT_REFERENCE` / tokens da timeline escalam com `windowWidth`.\n */\nexport const MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT = 390 as const\n\n/** Limite inferior do factor de escala (telefones mais estreitos). */\nexport const MOVIIE_SKIN_LAYOUT_SCALE_MIN = 0.72 as const\n\n/**\n * Limite superior do factor de escala: não aumenta além do design de referência em ecrãs largos.\n */\nexport const MOVIIE_SKIN_LAYOUT_SCALE_MAX = 1 as const\n\n/**\n * Distância do HUD inferior (tempo, marca) às bordas laterais do vídeo e ao padding interno do relógio —\n * valor na largura de referência ({@link MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT}).\n */\nexport const MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX = 6 as const\n\n/**\n * Espaço entre a linha do relógio/marca e o topo da área da timeline — referência.\n * Separado de {@link MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX} para poder encostar ao footer sem afetar margens horizontais.\n * Valor 0 = máximo colado (útil para experimentar layout).\n */\nexport const MOVIIE_SKIN_FLOATING_HUD_ABOVE_TIMELINE_GAP_AT_REFERENCE_PT = 0 as const\n\n/** Hit slop do wordmark e do fullscreen substituto no HUD inferior — px (valor físico independente da escala do layout). */\nexport const MOVIIE_SKIN_FLOATING_HUD_TRAILING_HIT_SLOP_PX = 8 as const\n\n/**\n * Diâmetro da película circular dos botões do HUD inferior (fullscreen, PiP, cast) — referência.\n */\nexport const MOVIIE_SKIN_FLOATING_FULLSCREEN_SCRIM_DIAMETER_AT_REFERENCE_PT = 44 as const\n\n/**\n * Tamanho do ícone dentro dessa película — referência.\n */\nexport const MOVIIE_SKIN_FLOATING_FULLSCREEN_ICON_AT_REFERENCE_PT = 26 as const\n\n/**\n * Ícones do canto superior (cast, PiP, fullscreen) sem película, com marca visível — referência.\n * Cada ícone aplica seu próprio fator de compensação visual sobre este valor, pois os\n * paths SVG têm densidades de preenchimento diferentes dentro do viewBox.\n */\nexport const MOVIIE_SKIN_FLOATING_FULLSCREEN_TOP_ICON_AT_REFERENCE_PT = 36 as const\n\n/**\n * Fatores de escala visual por ícone do canto superior.\n * Cast/PiP usam viewBox 0 0 24 24 (Material); Fullscreen usa viewBox 0 0 32 32 (media-icons 1.1.5).\n * As densidades de preenchimento são semelhantes entre si, mas Cast (Material 24px) ocupa mais\n * área visual que Fullscreen (32px com cantos L), daí o cast ter escala ligeiramente menor.\n */\nexport const MOVIIE_SKIN_TOP_ICON_CAST_VISUAL_SCALE = 0.65 as const\nexport const MOVIIE_SKIN_TOP_ICON_PIP_VISUAL_SCALE = 0.8 as const\nexport const MOVIIE_SKIN_TOP_ICON_FULLSCREEN_VISUAL_SCALE = 0.8 as const\n\n/**\n * Espaço entre botões da linha direita do HUD (cast, PiP, fullscreen) — referência.\n * Maior que {@link MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX} para evitar toques acidentais\n * em botões adjacentes.\n */\nexport const MOVIIE_SKIN_FLOATING_HUD_BUTTON_GAP_AT_REFERENCE_PT = 10 as const\n\n/** Raio dos cantos do indicador de tempo — valor na largura de referência. */\nexport const MOVIIE_SKIN_FLOATING_HUD_CLOCK_CORNER_RADIUS_PX = 6 as const\n\n/** Opacidade da película preta detrás dos botões de chrome (0–1). */\nexport const MOVIIE_SKIN_CHROME_SCRIM_BLACK_ALPHA = 0.5 as const\n\n/** Película preta por detrás dos elementos de chrome (timing, ícones). */\nexport const MOVIIE_SKIN_CHROME_SCRIM_BLACK_RGBA =\n `rgba(0,0,0,${MOVIIE_SKIN_CHROME_SCRIM_BLACK_ALPHA})` as const\n\n/** Opacidade dos controlos do chrome no estado normal (repouso). */\nexport const MOVIIE_SKIN_CHROME_CONTROL_REST_OPACITY = 1 as const\n\n/**\n * Opacidade dos controlos do chrome ao premir — feedback visual (seek, play, fullscreen).\n */\nexport const MOVIIE_SKIN_CHROME_CONTROL_PRESSED_OPACITY = 0.72 as const\n\n/** Preto nos stops do degradê vertical da skin (opacidade via `stopOpacity`). */\nexport const MOVIIE_SKIN_CHROME_GRADIENT_BLACK_HEX = '#000000' as const\n\n/** Opacidade na borda “cheia” do degradê (outro extremo é totalmente transparente). */\nexport const MOVIIE_SKIN_CHROME_GRADIENT_EDGE_ALPHA = 0.62 as const\n\n/**\n * Altura da faixa reservada ao degradê nas bordas — referência (maior = mais “respiro” transparente).\n * O escuro concentra-se junto à borda via {@link MOVIIE_SKIN_CHROME_EDGE_GRADIENT_EDGE_SOLID_FADE_END_FRACTION}.\n * O inferior acrescenta a altura da timeline quando a barra de progresso está visível.\n */\nexport const MOVIIE_SKIN_CHROME_EDGE_GRADIENT_HEIGHT_AT_REFERENCE_PT = 104 as const\n\n/**\n * Ao longo da faixa, fração [0–1] medida a partir da borda escura até estar 100% transparente.\n * Ex.: 0.48 → ~48% da altura da faixa com degradê; o resto é totalmente transparente (valor intermédio entre faixa longa e lábio rente à borda).\n */\nexport const MOVIIE_SKIN_CHROME_EDGE_GRADIENT_EDGE_SOLID_FADE_END_FRACTION = 0.48 as const\n\n/**\n * Altura mínima transparente entre faixa superior e inferior após escalar somas —\n * evita sobreposição das duas faixas (“película” em todo o vídeo).\n */\nexport const MOVIIE_SKIN_CHROME_EDGE_GRADIENT_MIN_CLEAR_MIDDLE_PX = 56 as const\n\n/** IDs estáveis para `LinearGradient` em SVG (skin chrome). */\nexport const MOVIIE_SKIN_CHROME_SVG_GRADIENT_BOTTOM_EDGE_ID =\n 'moviie_skin_chrome_gradient_bottom_edge' as const\n\nexport const MOVIIE_SKIN_CHROME_SVG_GRADIENT_TOP_EDGE_ID =\n 'moviie_skin_chrome_gradient_top_edge' as const\n\n/** Volume normalizado (0–1) abaixo disto usa o ícone `volume-low` como no Vidstack. */\nexport const MOVIIE_SKIN_VOLUME_LOW_ICON_THRESHOLD = 0.45 as const\n\n/** Foreground dos ícones e texto da skin (branco sólido). */\nexport const MOVIIE_SKIN_CHROME_FOREGROUND_HEX = '#ffffff' as const\n\n/**\n * Espelha valores numéricos de `OrientationLock` do pacote `expo-screen-orientation` (SDK 52).\n * Mantidos aqui para funções puras e testes Vitest sem resolver o entry nativo do Expo.\n */\nexport const MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE = {\n LANDSCAPE: 5,\n LANDSCAPE_LEFT: 6,\n LANDSCAPE_RIGHT: 7,\n} as const\n\nexport type MoviieExpoOrientationLockValue =\n (typeof MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE)[keyof typeof MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE]\n\n/** Duração da transição (rotação + escala) do fullscreen JS na skin Moviie. */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_TRANSITION_MS = 420 as const\n\n/**\n * Rotação final em graus no eixo Z (sentido horário no React Native): vídeo + chrome giram juntos.\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_ROTATE_Z_DEGREES = 90 as const\n\n/** Escala inicial ao entrar em fullscreen (anima até 1). Saída anima de 1 até este valor. */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_ENTER_SCALE_START = 0.78 as const\n\n/**\n * `contentFit` no fullscreen rotacionado: preenche a altura útil do palco; barras laterais ficam a preto do palco.\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_VIDEO_CONTENT_FIT = 'contain' as const\n\n/** Fundo do palco em fullscreen JS e placeholder inline durante o modo expandido. */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_BACKGROUND_HEX = '#000000' as const\n\n/**\n * Margem extra (dp/pt) para dentro dos safe area insets no palco fullscreen rotacionado —\n * evita cortar chrome por cantos redondos / overshoot da animação.\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_OVERSCAN_PX = 12 as const\n\n/**\n * Reforço da margem do HUD/timeline em fullscreen rotacionado (escala com {@link MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT}).\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_HUD_EDGE_BOOST_REFERENCE_PT = 14 as const\n\n/** Margem de buffer (s) abaixo da cabeça de reprodução para detetar stalls em HLS. */\nexport const MOVIIE_SKIN_BUFFER_UNDERRUN_LEAD_SECONDS = 0.35 as const\n\nexport const MOVIIE_SKIN_SEEK_JUMP_SECONDS = 10 as const\n\nexport const MOVIIE_SKIN_CENTER_PLAY_ICON_PX = 40 as const\n\n/**\n * Diâmetro da película circular do play/pause central — referência.\n * Entre o círculo compacto (~52) e o layout antigo (~108 na referência).\n */\nexport const MOVIIE_SKIN_CENTER_PLAY_SCRIM_DIAMETER_AT_REFERENCE_PT = 80 as const\n\n/**\n * Diâmetro da película circular dos botões seek (±10 s) junto ao play — referência.\n * Compacto em torno do ícone ({@link MOVIIE_SKIN_SEEK_ICON_PX}); inferior ao play.\n */\nexport const MOVIIE_SKIN_CENTER_SEEK_SCRIM_DIAMETER_AT_REFERENCE_PT = 46 as const\n\n/** Ícone seek ±10 s no cluster central — referência (escala com layout). */\nexport const MOVIIE_SKIN_SEEK_ICON_PX = 28 as const\n\n/** Espaço horizontal entre botões do cluster central — valor na largura de referência. */\nexport const MOVIIE_SKIN_CENTER_CLUSTER_COLUMN_GAP_PX = 12 as const\n\n/** Tamanho do texto do relógio — valor na largura de referência. */\nexport const MOVIIE_SKIN_CLOCK_TEXT_FONT_SIZE_AT_REFERENCE_PT = 12 as const\n\n/** Altura da faixa única da timeline — valor na largura de referência. */\nexport const MOVIIE_SKIN_TIMELINE_BAR_HEIGHT_PX = 3 as const\n\n/** Diâmetro do thumb de scrub — valor na largura de referência. */\nexport const MOVIIE_SKIN_TIMELINE_THUMB_DIAMETER_PX = 14 as const\n\n/** Padding vertical acima da timeline — referência (0 = mínimo para testes de densidade). */\nexport const MOVIIE_SKIN_TIMELINE_TOUCH_PADDING_VERTICAL_PX = 0 as const\n\n/**\n * Padding vertical mínimo (dp lógico) por cima do rail dentro da área do vídeo — bem menor que antes:\n * o alvo tátil prioritário é {@link MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_BOTTOM_DP} por baixo do frame.\n */\nexport const MOVIIE_SKIN_TIMELINE_TOUCH_EXPANSION_VERTICAL_DP = 2 as const\n\n/**\n * Expansão lateral modesta (`View.hitSlop`) — evita faixa enorme dentro do vídeo.\n */\nexport const MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_HORIZONTAL_DP = 3 as const\n\n/**\n * Pouca expansão para cima: apenas cobrir metade superior do thumb / gestos desde logo acima do trilho.\n */\nexport const MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_TOP_DP = 2 as const\n\n/**\n * Expansão inferior dominante — cobre o thumb quando ultrapassa o limite inferior do vídeo\n * (`hitSlop` não ocupa layout dentro do frame; toques contam por baixo da overlay).\n */\nexport const MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_BOTTOM_DP = 14 as const\n\n/** Trilho base da timeline: branco ~30%. */\nexport const MOVIIE_SKIN_TIMELINE_RAIL_BACKGROUND_RGBA = 'rgba(255,255,255,0.3)' as const\n\n/** Camada de buffer sobre o trilho (mesma cor/opacidade que o trilho). */\nexport const MOVIIE_SKIN_TIMELINE_BUFFER_LAYER_RGBA = MOVIIE_SKIN_TIMELINE_RAIL_BACKGROUND_RGBA\n\n/** Contorno do thumb da timeline para contraste sobre vídeo claro. */\nexport const MOVIIE_SKIN_TIMELINE_THUMB_BORDER_RGBA = 'rgba(0,0,0,0.35)' as const\n\n/** Diâmetro do thumb durante scrub (drag) relativamente ao thumb em repouso. */\nexport const MOVIIE_SKIN_TIMELINE_THUMB_DRAG_DIAMETER_MULTIPLIER = 1.65 as const\n\n/**\n * Segundos antes do fim onde o progresso mostrado fixa em 100% quando não está a reproduzir —\n * o `currentTime` do motor costuma ficar ligeiramente abaixo de `duration` no fim.\n */\nexport const MOVIIE_SKIN_TIMELINE_END_SNAP_EPSILON_SECONDS = 0.15 as const\n\n/**\n * Distância máxima (s) entre a posição de release do scrub e um boundary de capítulo\n * para que o snap automático seja ativado.\n */\nexport const MOVIIE_SKIN_TIMELINE_CHAPTER_SNAP_THRESHOLD_SECONDS = 2 as const\n\n/** Área do `ActivityIndicator` small no overlay de buffering — valor na largura de referência. */\nexport const MOVIIE_SKIN_BUFFERING_INDICATOR_SLOT_PX = 28 as const\n\n/** Largura intrínseca do SVG wordmark (viewBox). */\nexport const MOVIIE_SKIN_BRAND_MARK_ARTBOARD_WIDTH_PX = 173 as const\n\n/** Altura intrínseca do SVG wordmark (viewBox). */\nexport const MOVIIE_SKIN_BRAND_MARK_ARTBOARD_HEIGHT_PX = 46 as const\n\n/**\n * Largura visual alvo do wordmark quando `windowWidth` = {@link MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT}\n * (entre o tamanho compacto antigo e o artboard completo).\n */\nexport const MOVIIE_SKIN_BRAND_MARK_TARGET_WIDTH_AT_REFERENCE_PT = 68 as const\n\n/** ViewBox do SVG wordmark Moviie (173×46). */\nexport const MOVIIE_EMBED_BRAND_VIEW_BOX = '0 0 173 46' as const\n\n/** Espessura do traço das letras “ii” no wordmark (coordenadas do viewBox). */\nexport const MOVIIE_EMBED_BRAND_LETTERMARK_STROKE_WIDTH = 3 as const\n","/**\n * Configura endpoints da API Moviie a partir de **variáveis de ambiente**\n * `EXPO_PUBLIC_MOVIIE_API_BASE_URL` e (raro) `EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL`.\n *\n * **Override é apenas para desenvolvimento local.** Apps em produção usam o\n * default `https://api.moviie.ai/v1`. Por isso este módulo:\n *\n * - Só aplica o override quando `__DEV__ === true` (Metro/Hermes dev mode);\n * - Não depende de `expo-constants` — usa só `process.env.*` que o Metro inlina\n * em build time para qualquer var `EXPO_PUBLIC_*`;\n * - Falha silenciosamente em produção (var inexistente → default do SDK).\n *\n * Vars relevantes (definidas em `.env.local` no consumer):\n * EXPO_PUBLIC_MOVIIE_API_BASE_URL=http://localhost:3000/api/v1\n * EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL=http://localhost:3000/telemetry/v1\n */\nimport { configureMoviieEndpoints } from '@moviie/player-sdk'\n\nimport {\n EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV,\n EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV,\n} from './constants'\n\nfunction normalize(raw: string | undefined): string | undefined {\n if (typeof raw !== 'string') return undefined\n const trimmed = raw.trim()\n return trimmed.length > 0 ? trimmed.replace(/\\/+$/, '') : undefined\n}\n\n// `__DEV__` é definido pelo bundler RN. Em web build (Vite/Next) cai pra `process.env.NODE_ENV`.\nconst devMode =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production'\n\nif (devMode) {\n const apiBaseUrl = normalize(process.env[EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV])\n const eventsBaseUrl = normalize(process.env[EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV])\n\n const opts: { apiBaseUrl?: string; eventsBaseUrl?: string } = {}\n if (apiBaseUrl != null) opts.apiBaseUrl = apiBaseUrl\n if (eventsBaseUrl != null) opts.eventsBaseUrl = eventsBaseUrl\n\n if (opts.apiBaseUrl != null || opts.eventsBaseUrl != null) {\n configureMoviieEndpoints(opts)\n }\n}\n","/**\n * Console warning idempotente por chave. Útil para dependências opcionais ausentes:\n * dispara uma única vez por sessão para a mesma chave, evitando ruído no console.\n *\n * Reusável para qualquer feature gated por dep opcional (cast, DRM custom,\n * analytics provider, etc.).\n */\n\nconst FIRED_KEYS = new Set<string>()\n\nexport function warnOnce(key: string, message: string): void {\n if (FIRED_KEYS.has(key)) {\n return\n }\n FIRED_KEYS.add(key)\n // eslint-disable-next-line no-console\n console.warn(message)\n}\n\n/** Limpa o set de chaves disparadas. Use apenas em testes. */\nexport function __resetWarnOnceForTests(): void {\n FIRED_KEYS.clear()\n}\n","import type { ViewerTokenStore } from '@moviie/player-sdk'\nimport { MemoryViewerTokenStore } from '@moviie/player-sdk'\n\nimport { warnOnce } from './lib/warn-once'\n\nexport const MOVIIE_VIEWER_TOKEN_SECURE_STORE_KEY = 'moviie_viewer_token_v1' as const\n\nconst SECURE_STORE_MISSING_WARNING =\n '[@moviie/player-expo] `expo-secure-store` não está instalado — viewer token será mantido apenas em memória (perde ao matar app). ' +\n 'Instala com `pnpm add expo-secure-store` se quiseres persistência entre sessões.'\n\ninterface StoredEnvelope {\n token: string\n expiresAt: number\n}\n\nfunction isStoredEnvelope(value: unknown): value is StoredEnvelope {\n if (!value || typeof value !== 'object') return false\n const v = value as Record<string, unknown>\n return typeof v.token === 'string' && typeof v.expiresAt === 'number'\n}\n\nexport class SecureStoreViewerTokenStore implements ViewerTokenStore {\n private readonly fallback: ViewerTokenStore\n private readonly storageKey: string\n\n constructor(options?: { fallback?: ViewerTokenStore; storageKey?: string }) {\n this.fallback = options?.fallback ?? new MemoryViewerTokenStore()\n this.storageKey = options?.storageKey ?? MOVIIE_VIEWER_TOKEN_SECURE_STORE_KEY\n }\n\n private async loadSecureStore(): Promise<typeof import('expo-secure-store') | null> {\n try {\n return await import('expo-secure-store')\n } catch {\n warnOnce('moviie:expo-secure-store-missing', SECURE_STORE_MISSING_WARNING)\n return null\n }\n }\n\n async get(): Promise<string | null> {\n const SecureStore = await this.loadSecureStore()\n if (!SecureStore) {\n return this.fallback.get()\n }\n try {\n const raw = await SecureStore.getItemAsync(this.storageKey)\n if (!raw) return null\n const parsed: unknown = JSON.parse(raw)\n if (!isStoredEnvelope(parsed)) {\n await SecureStore.deleteItemAsync(this.storageKey).catch(() => {})\n return null\n }\n if (parsed.expiresAt <= Date.now()) {\n await SecureStore.deleteItemAsync(this.storageKey).catch(() => {})\n return null\n }\n return parsed.token\n } catch {\n return this.fallback.get()\n }\n }\n\n async set(token: string, ttlSec: number): Promise<void> {\n const SecureStore = await this.loadSecureStore()\n const envelope: StoredEnvelope = {\n token,\n expiresAt: Date.now() + Math.max(0, ttlSec) * 1000,\n }\n if (!SecureStore) {\n await this.fallback.set(token, ttlSec)\n return\n }\n try {\n await SecureStore.setItemAsync(this.storageKey, JSON.stringify(envelope))\n } catch {\n await this.fallback.set(token, ttlSec)\n }\n }\n}\n","import * as Application from \"expo-application\"\n\nexport function readNativeApplicationId(): string | undefined {\n try {\n const id = Application.applicationId\n return id ?? undefined\n } catch {\n return undefined\n }\n}\n","import { Platform } from \"react-native\"\n\nimport type { MoviieClientInfo } from \"@moviie/player-sdk\"\n\nimport { readNativeApplicationId } from \"./native-application-id\"\n\nlet cached: MoviieClientInfo | null = null\n\nexport function buildPlatformClientInfo(sdkVersion: string): MoviieClientInfo {\n if (cached) {\n return cached\n }\n\n const os = Platform.OS\n const platform: MoviieClientInfo[\"platform\"] =\n os === \"ios\" ? \"ios\" : os === \"android\" ? \"android\" : \"web\"\n\n const bundleId =\n platform === \"web\" ? undefined : readNativeApplicationId()\n\n cached = {\n platform,\n bundleId,\n sdkVersion,\n }\n return cached\n}\n\nexport function resetPlatformClientInfoCache(): void {\n cached = null\n}\n","import {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\"\n\nimport {\n buildClientHeaders,\n MemoryViewerTokenStore,\n MoviieClient,\n type MoviieClientInfo,\n type ViewerTokenStore,\n} from \"@moviie/player-sdk\"\n\nimport { MOVIIE_PLAYER_EXPO_PKG_VERSION } from \"../constants\"\nimport { buildPlatformClientInfo } from \"../platform/platform-client-info\"\nimport { SecureStoreViewerTokenStore } from \"../secure-store-viewer-token-store\"\n\nexport interface MoviieContextValue {\n client: MoviieClient\n viewerTokenStore: ViewerTokenStore\n publishableKey: string | null\n clientInfo: MoviieClientInfo\n sdkVersion: string\n /** Headers reused by TelemetryClient (Bearer + X-Moviie-Client when aplicável) */\n telemetryHeaders: Record<string, string>\n}\n\nconst MoviieContext = createContext<MoviieContextValue | null>(null)\n\nlet fallbackContext: MoviieContextValue | null = null\n\nfunction getOrCreateFallbackContext(): MoviieContextValue {\n if (!fallbackContext) {\n const sdkVersion = MOVIIE_PLAYER_EXPO_PKG_VERSION\n const clientInfo = buildPlatformClientInfo(sdkVersion)\n const viewerTokenStore = new MemoryViewerTokenStore()\n const client = new MoviieClient({\n publishableKey: undefined,\n clientInfo,\n sdkVersion,\n })\n fallbackContext = {\n client,\n viewerTokenStore,\n publishableKey: null,\n clientInfo,\n sdkVersion,\n telemetryHeaders: buildClientHeaders({\n clientInfo,\n sdkVersion,\n }),\n }\n }\n return fallbackContext\n}\n\nexport function useMoviieContext(): MoviieContextValue {\n const ctx = useContext(MoviieContext)\n return ctx ?? getOrCreateFallbackContext()\n}\n\nexport function MoviieProvider({\n publishableKey,\n children,\n}: {\n publishableKey?: string | null\n children: ReactNode\n}) {\n const value = useMemo((): MoviieContextValue => {\n const sdkVersion = MOVIIE_PLAYER_EXPO_PKG_VERSION\n const clientInfo = buildPlatformClientInfo(sdkVersion)\n const trimmedKey = publishableKey?.trim()\n const viewerTokenStore = new SecureStoreViewerTokenStore()\n const client = new MoviieClient({\n publishableKey: trimmedKey || undefined,\n clientInfo,\n sdkVersion,\n })\n const telemetryHeaders = buildClientHeaders({\n publishableKey: trimmedKey || undefined,\n clientInfo,\n sdkVersion,\n })\n return {\n client,\n viewerTokenStore,\n publishableKey: trimmedKey ?? null,\n clientInfo,\n sdkVersion,\n telemetryHeaders,\n }\n }, [publishableKey])\n\n return (\n <MoviieContext.Provider value={value}>{children}</MoviieContext.Provider>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/apply-expo-moviie-endpoints.ts","../src/lib/warn-once.ts","../src/secure-store-viewer-token-store.ts","../src/platform/native-application-id.ts","../src/platform/platform-client-info.ts","../src/provider/moviie-provider.tsx"],"names":["MemoryViewerTokenStore"],"mappings":"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","file":"chunk-5P3BQYRP.mjs","sourcesContent":["export const MOVIIE_PLAYER_EXPO_PKG_VERSION = '0.5.1' as const\n\nexport const MOVIIE_PLAYBACK_MEMORY_CACHE_TTL_MS = 5 * 60 * 1000\n\n/** Playback profile strings returned by the playback API (aligned with web embed). */\nexport const MOVIIE_PLAYBACK_PROFILE = {\n VSL: 'vsl',\n CUSTOM: 'custom',\n} as const\n\n/**\n * Smart Progress curve — mirrors {@link SMART_PROGRESS_CONFIG} on the web embed\n * (`apps/web/src/app/embed/[id]/constants.ts`).\n */\nexport const MOVIIE_SMART_PROGRESS_CONFIG = {\n R1: 0.18,\n P1: 0.62,\n R2: 0.8,\n P2: 0.95,\n P_MAX_BEFORE_END: 0.99,\n} as const\n\n/** Fill animation duration (ms); aligns with web `.moviie-smart-progress-fill` transition. */\nexport const MOVIIE_SMART_PROGRESS_FILL_TRANSITION_MS = 150 as const\n\n/** Absolute bottom bar height (dp) for native Smart Progress strip. */\nexport const MOVIIE_SMART_PROGRESS_BAR_HEIGHT_DP = 12 as const\n\nexport const MOVIIE_SMART_PROGRESS_Z_INDEX = 34 as const\n\n/**\n * SecureStore key prefix for resume position (`{prefix}{embedId}`).\n * Embed IDs are UUIDs from the API.\n */\nexport const MOVIIE_REMEMBER_POSITION_STORAGE_PREFIX = 'moviie.resume_position.' as const\n\n/** Debounce interval before persisting resume position while playing. */\nexport const MOVIIE_REMEMBER_POSITION_DEBOUNCE_MS = 5000 as const\n\n/** Matches embed/web framing defaults when `contentFit` is omitted on `MoviieVideo`. */\nexport const MOVIIE_VIDEO_DEFAULT_CONTENT_FIT = {\n VERTICAL: 'contain',\n HORIZONTAL: 'cover',\n} as const\n\nexport const MOVIIE_BRANDING_MARKETING_ORIGIN = 'https://moviie.ai' as const\n\n/** Origin público da página watch/embed (sem barra final). Override: `EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN`. */\nexport const MOVIIE_WATCH_ORIGIN_DEFAULT = 'https://watch.moviie.ai' as const\n\n/**\n * Variável `EXPO_PUBLIC_*` para override do origin watch/embed em Expo Web (`resolveMoviieWatchOrigin`).\n */\nexport const EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN_ENV = 'EXPO_PUBLIC_MOVIIE_WATCH_ORIGIN' as const\n\n/** Path público do script da API JS do embed (relativo ao watch origin). */\nexport const MOVIIE_WATCH_EMBED_JS_PATH = '/embed.js' as const\n\n/**\n * Atributo único no `<script>` injectado em Expo Web para evitar duplicar `embed.js`\n * quando há vários `MoviieVideo` montados.\n */\nexport const MOVIIE_PLAYER_EXPO_EMBED_JS_MARKER_ATTR = 'data-moviie-player-expo-embed-js' as const\n\n/**\n * Variável `EXPO_PUBLIC_*` que override a base da API Moviie em **dev only**.\n * O Metro inlina qualquer `EXPO_PUBLIC_*` em build time, sem precisar de\n * `expo-constants`. Em produção o SDK usa sempre o default `https://api.moviie.ai/v1`.\n *\n * Exemplo `.env.local`:\n * EXPO_PUBLIC_MOVIIE_API_BASE_URL=http://localhost:3000/api/v1\n */\nexport const EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV = 'EXPO_PUBLIC_MOVIIE_API_BASE_URL' as const\n\n/**\n * Variável `EXPO_PUBLIC_*` que override a base de telemetria em **dev only**.\n * Caso omitida, deriva-se de `{origin}/telemetry/v1` a partir de `apiBaseUrl`.\n */\nexport const EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV = 'EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL' as const\n\nexport const MOVIIE_BRANDING_UTM_PARAM_SOURCE = 'utm_source' as const\nexport const MOVIIE_BRANDING_UTM_PARAM_MEDIUM = 'utm_medium' as const\nexport const MOVIIE_BRANDING_UTM_PARAM_CAMPAIGN = 'utm_campaign' as const\n\nexport const MOVIIE_BRANDING_UTM_SOURCE_VALUE = 'player-expo' as const\nexport const MOVIIE_BRANDING_UTM_MEDIUM_VALUE = 'branding' as const\n\n/** Espelha `PLAYER_EMBED_BRAND_UTM` do embed web (`apps/web/src/app/embed/[id]/constants.ts`). */\nexport const MOVIIE_EMBED_BRAND_UTM = {\n SOURCE: 'moviie_embed_player',\n MEDIUM: 'video_control_bar',\n CAMPAIGN: 'logo_click',\n} as const\n\nexport const MOVIIE_SKIN_DEFAULT_ACCENT_HEX = '#6366f1' as const\n\n/**\n * Valor legado para a prop `controlsAutoHideMs` / `autoHideMs`: o chrome da skin Moviie já não\n * usa temporizador para ocultar — só ao toque fora ou ações (play, seek).\n */\nexport const MOVIIE_SKIN_CONTROLS_AUTO_HIDE_MS = 3000 as const\n\nexport const MOVIIE_SKIN_CONTROLS_FADE_MS = 240 as const\n\nexport const MOVIIE_SKIN_WATERMARK_OPACITY = 0.7 as const\n\nexport const MOVIIE_SKIN_CONTROL_ICON_PX = 22 as const\n\n/**\n * Largura lógica de referência do layout da skin (ex.: frame Figma / iPhone ~390pt).\n * Dimensões em `MOVIIE_SKIN_*_AT_REFERENCE` / tokens da timeline escalam com `windowWidth`.\n */\nexport const MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT = 390 as const\n\n/** Limite inferior do factor de escala (telefones mais estreitos). */\nexport const MOVIIE_SKIN_LAYOUT_SCALE_MIN = 0.72 as const\n\n/**\n * Limite superior do factor de escala: não aumenta além do design de referência em ecrãs largos.\n */\nexport const MOVIIE_SKIN_LAYOUT_SCALE_MAX = 1 as const\n\n/**\n * Distância do HUD inferior (tempo, marca) às bordas laterais do vídeo e ao padding interno do relógio —\n * valor na largura de referência ({@link MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT}).\n */\nexport const MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX = 6 as const\n\n/**\n * Espaço entre a linha do relógio/marca e o topo da área da timeline — referência.\n * Separado de {@link MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX} para poder encostar ao footer sem afetar margens horizontais.\n * Valor 0 = máximo colado (útil para experimentar layout).\n */\nexport const MOVIIE_SKIN_FLOATING_HUD_ABOVE_TIMELINE_GAP_AT_REFERENCE_PT = 0 as const\n\n/** Hit slop do wordmark e do fullscreen substituto no HUD inferior — px (valor físico independente da escala do layout). */\nexport const MOVIIE_SKIN_FLOATING_HUD_TRAILING_HIT_SLOP_PX = 8 as const\n\n/**\n * Diâmetro da película circular dos botões do HUD inferior (fullscreen, PiP, cast) — referência.\n */\nexport const MOVIIE_SKIN_FLOATING_FULLSCREEN_SCRIM_DIAMETER_AT_REFERENCE_PT = 44 as const\n\n/**\n * Tamanho do ícone dentro dessa película — referência.\n */\nexport const MOVIIE_SKIN_FLOATING_FULLSCREEN_ICON_AT_REFERENCE_PT = 26 as const\n\n/**\n * Ícones do canto superior (cast, PiP, fullscreen) sem película, com marca visível — referência.\n * Cada ícone aplica seu próprio fator de compensação visual sobre este valor, pois os\n * paths SVG têm densidades de preenchimento diferentes dentro do viewBox.\n */\nexport const MOVIIE_SKIN_FLOATING_FULLSCREEN_TOP_ICON_AT_REFERENCE_PT = 36 as const\n\n/**\n * Fatores de escala visual por ícone do canto superior.\n * Cast/PiP usam viewBox 0 0 24 24 (Material); Fullscreen usa viewBox 0 0 32 32 (media-icons 1.1.5).\n * As densidades de preenchimento são semelhantes entre si, mas Cast (Material 24px) ocupa mais\n * área visual que Fullscreen (32px com cantos L), daí o cast ter escala ligeiramente menor.\n */\nexport const MOVIIE_SKIN_TOP_ICON_CAST_VISUAL_SCALE = 0.65 as const\nexport const MOVIIE_SKIN_TOP_ICON_PIP_VISUAL_SCALE = 0.8 as const\nexport const MOVIIE_SKIN_TOP_ICON_FULLSCREEN_VISUAL_SCALE = 0.8 as const\n\n/**\n * Espaço entre botões da linha direita do HUD (cast, PiP, fullscreen) — referência.\n * Maior que {@link MOVIIE_SKIN_FLOATING_HUD_EDGE_INSET_PX} para evitar toques acidentais\n * em botões adjacentes.\n */\nexport const MOVIIE_SKIN_FLOATING_HUD_BUTTON_GAP_AT_REFERENCE_PT = 10 as const\n\n/** Raio dos cantos do indicador de tempo — valor na largura de referência. */\nexport const MOVIIE_SKIN_FLOATING_HUD_CLOCK_CORNER_RADIUS_PX = 6 as const\n\n/** Opacidade da película preta detrás dos botões de chrome (0–1). */\nexport const MOVIIE_SKIN_CHROME_SCRIM_BLACK_ALPHA = 0.5 as const\n\n/** Película preta por detrás dos elementos de chrome (timing, ícones). */\nexport const MOVIIE_SKIN_CHROME_SCRIM_BLACK_RGBA =\n `rgba(0,0,0,${MOVIIE_SKIN_CHROME_SCRIM_BLACK_ALPHA})` as const\n\n/** Opacidade dos controlos do chrome no estado normal (repouso). */\nexport const MOVIIE_SKIN_CHROME_CONTROL_REST_OPACITY = 1 as const\n\n/**\n * Opacidade dos controlos do chrome ao premir — feedback visual (seek, play, fullscreen).\n */\nexport const MOVIIE_SKIN_CHROME_CONTROL_PRESSED_OPACITY = 0.72 as const\n\n/** Preto nos stops do degradê vertical da skin (opacidade via `stopOpacity`). */\nexport const MOVIIE_SKIN_CHROME_GRADIENT_BLACK_HEX = '#000000' as const\n\n/** Opacidade na borda “cheia” do degradê (outro extremo é totalmente transparente). */\nexport const MOVIIE_SKIN_CHROME_GRADIENT_EDGE_ALPHA = 0.62 as const\n\n/**\n * Altura da faixa reservada ao degradê nas bordas — referência (maior = mais “respiro” transparente).\n * O escuro concentra-se junto à borda via {@link MOVIIE_SKIN_CHROME_EDGE_GRADIENT_EDGE_SOLID_FADE_END_FRACTION}.\n * O inferior acrescenta a altura da timeline quando a barra de progresso está visível.\n */\nexport const MOVIIE_SKIN_CHROME_EDGE_GRADIENT_HEIGHT_AT_REFERENCE_PT = 104 as const\n\n/**\n * Ao longo da faixa, fração [0–1] medida a partir da borda escura até estar 100% transparente.\n * Ex.: 0.48 → ~48% da altura da faixa com degradê; o resto é totalmente transparente (valor intermédio entre faixa longa e lábio rente à borda).\n */\nexport const MOVIIE_SKIN_CHROME_EDGE_GRADIENT_EDGE_SOLID_FADE_END_FRACTION = 0.48 as const\n\n/**\n * Altura mínima transparente entre faixa superior e inferior após escalar somas —\n * evita sobreposição das duas faixas (“película” em todo o vídeo).\n */\nexport const MOVIIE_SKIN_CHROME_EDGE_GRADIENT_MIN_CLEAR_MIDDLE_PX = 56 as const\n\n/** IDs estáveis para `LinearGradient` em SVG (skin chrome). */\nexport const MOVIIE_SKIN_CHROME_SVG_GRADIENT_BOTTOM_EDGE_ID =\n 'moviie_skin_chrome_gradient_bottom_edge' as const\n\nexport const MOVIIE_SKIN_CHROME_SVG_GRADIENT_TOP_EDGE_ID =\n 'moviie_skin_chrome_gradient_top_edge' as const\n\n/** Volume normalizado (0–1) abaixo disto usa o ícone `volume-low` como no Vidstack. */\nexport const MOVIIE_SKIN_VOLUME_LOW_ICON_THRESHOLD = 0.45 as const\n\n/** Foreground dos ícones e texto da skin (branco sólido). */\nexport const MOVIIE_SKIN_CHROME_FOREGROUND_HEX = '#ffffff' as const\n\n/**\n * Espelha valores numéricos de `OrientationLock` do pacote `expo-screen-orientation` (SDK 52).\n * Mantidos aqui para funções puras e testes Vitest sem resolver o entry nativo do Expo.\n */\nexport const MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE = {\n LANDSCAPE: 5,\n LANDSCAPE_LEFT: 6,\n LANDSCAPE_RIGHT: 7,\n} as const\n\nexport type MoviieExpoOrientationLockValue =\n (typeof MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE)[keyof typeof MOVIIE_EXPO_SCREEN_ORIENTATION_LOCK_VALUE]\n\n/** Duração da transição (rotação + escala) do fullscreen JS na skin Moviie. */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_TRANSITION_MS = 420 as const\n\n/**\n * Rotação final em graus no eixo Z (sentido horário no React Native): vídeo + chrome giram juntos.\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_ROTATE_Z_DEGREES = 90 as const\n\n/** Escala inicial ao entrar em fullscreen (anima até 1). Saída anima de 1 até este valor. */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_ENTER_SCALE_START = 0.78 as const\n\n/**\n * `contentFit` no fullscreen rotacionado: preenche a altura útil do palco; barras laterais ficam a preto do palco.\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_VIDEO_CONTENT_FIT = 'contain' as const\n\n/** Fundo do palco em fullscreen JS e placeholder inline durante o modo expandido. */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_BACKGROUND_HEX = '#000000' as const\n\n/**\n * Margem extra (dp/pt) para dentro dos safe area insets no palco fullscreen rotacionado —\n * evita cortar chrome por cantos redondos / overshoot da animação.\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_STAGE_OVERSCAN_PX = 12 as const\n\n/**\n * Reforço da margem do HUD/timeline em fullscreen rotacionado (escala com {@link MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT}).\n */\nexport const MOVIIE_SKIN_CUSTOM_FULLSCREEN_HUD_EDGE_BOOST_REFERENCE_PT = 14 as const\n\n/** Margem de buffer (s) abaixo da cabeça de reprodução para detetar stalls em HLS. */\nexport const MOVIIE_SKIN_BUFFER_UNDERRUN_LEAD_SECONDS = 0.35 as const\n\nexport const MOVIIE_SKIN_SEEK_JUMP_SECONDS = 10 as const\n\nexport const MOVIIE_SKIN_CENTER_PLAY_ICON_PX = 40 as const\n\n/**\n * Diâmetro da película circular do play/pause central — referência.\n * Entre o círculo compacto (~52) e o layout antigo (~108 na referência).\n */\nexport const MOVIIE_SKIN_CENTER_PLAY_SCRIM_DIAMETER_AT_REFERENCE_PT = 80 as const\n\n/**\n * Diâmetro da película circular dos botões seek (±10 s) junto ao play — referência.\n * Compacto em torno do ícone ({@link MOVIIE_SKIN_SEEK_ICON_PX}); inferior ao play.\n */\nexport const MOVIIE_SKIN_CENTER_SEEK_SCRIM_DIAMETER_AT_REFERENCE_PT = 46 as const\n\n/** Ícone seek ±10 s no cluster central — referência (escala com layout). */\nexport const MOVIIE_SKIN_SEEK_ICON_PX = 28 as const\n\n/** Espaço horizontal entre botões do cluster central — valor na largura de referência. */\nexport const MOVIIE_SKIN_CENTER_CLUSTER_COLUMN_GAP_PX = 12 as const\n\n/** Tamanho do texto do relógio — valor na largura de referência. */\nexport const MOVIIE_SKIN_CLOCK_TEXT_FONT_SIZE_AT_REFERENCE_PT = 12 as const\n\n/** Altura da faixa única da timeline — valor na largura de referência. */\nexport const MOVIIE_SKIN_TIMELINE_BAR_HEIGHT_PX = 3 as const\n\n/** Diâmetro do thumb de scrub — valor na largura de referência. */\nexport const MOVIIE_SKIN_TIMELINE_THUMB_DIAMETER_PX = 14 as const\n\n/** Padding vertical acima da timeline — referência (0 = mínimo para testes de densidade). */\nexport const MOVIIE_SKIN_TIMELINE_TOUCH_PADDING_VERTICAL_PX = 0 as const\n\n/**\n * Padding vertical mínimo (dp lógico) por cima do rail dentro da área do vídeo — bem menor que antes:\n * o alvo tátil prioritário é {@link MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_BOTTOM_DP} por baixo do frame.\n */\nexport const MOVIIE_SKIN_TIMELINE_TOUCH_EXPANSION_VERTICAL_DP = 2 as const\n\n/**\n * Expansão lateral modesta (`View.hitSlop`) — evita faixa enorme dentro do vídeo.\n */\nexport const MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_HORIZONTAL_DP = 3 as const\n\n/**\n * Pouca expansão para cima: apenas cobrir metade superior do thumb / gestos desde logo acima do trilho.\n */\nexport const MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_TOP_DP = 2 as const\n\n/**\n * Expansão inferior dominante — cobre o thumb quando ultrapassa o limite inferior do vídeo\n * (`hitSlop` não ocupa layout dentro do frame; toques contam por baixo da overlay).\n */\nexport const MOVIIE_SKIN_TIMELINE_SCRUB_HIT_SLOP_BOTTOM_DP = 14 as const\n\n/** Trilho base da timeline: branco ~30%. */\nexport const MOVIIE_SKIN_TIMELINE_RAIL_BACKGROUND_RGBA = 'rgba(255,255,255,0.3)' as const\n\n/** Camada de buffer sobre o trilho (mesma cor/opacidade que o trilho). */\nexport const MOVIIE_SKIN_TIMELINE_BUFFER_LAYER_RGBA = MOVIIE_SKIN_TIMELINE_RAIL_BACKGROUND_RGBA\n\n/** Contorno do thumb da timeline para contraste sobre vídeo claro. */\nexport const MOVIIE_SKIN_TIMELINE_THUMB_BORDER_RGBA = 'rgba(0,0,0,0.35)' as const\n\n/** Diâmetro do thumb durante scrub (drag) relativamente ao thumb em repouso. */\nexport const MOVIIE_SKIN_TIMELINE_THUMB_DRAG_DIAMETER_MULTIPLIER = 1.65 as const\n\n/**\n * Segundos antes do fim onde o progresso mostrado fixa em 100% quando não está a reproduzir —\n * o `currentTime` do motor costuma ficar ligeiramente abaixo de `duration` no fim.\n */\nexport const MOVIIE_SKIN_TIMELINE_END_SNAP_EPSILON_SECONDS = 0.15 as const\n\n/**\n * Distância máxima (s) entre a posição de release do scrub e um boundary de capítulo\n * para que o snap automático seja ativado.\n */\nexport const MOVIIE_SKIN_TIMELINE_CHAPTER_SNAP_THRESHOLD_SECONDS = 2 as const\n\n/** Área do `ActivityIndicator` small no overlay de buffering — valor na largura de referência. */\nexport const MOVIIE_SKIN_BUFFERING_INDICATOR_SLOT_PX = 28 as const\n\n/** Largura intrínseca do SVG wordmark (viewBox). */\nexport const MOVIIE_SKIN_BRAND_MARK_ARTBOARD_WIDTH_PX = 173 as const\n\n/** Altura intrínseca do SVG wordmark (viewBox). */\nexport const MOVIIE_SKIN_BRAND_MARK_ARTBOARD_HEIGHT_PX = 46 as const\n\n/**\n * Largura visual alvo do wordmark quando `windowWidth` = {@link MOVIIE_SKIN_LAYOUT_REFERENCE_WIDTH_PT}\n * (entre o tamanho compacto antigo e o artboard completo).\n */\nexport const MOVIIE_SKIN_BRAND_MARK_TARGET_WIDTH_AT_REFERENCE_PT = 68 as const\n\n/** ViewBox do SVG wordmark Moviie (173×46). */\nexport const MOVIIE_EMBED_BRAND_VIEW_BOX = '0 0 173 46' as const\n\n/** Espessura do traço das letras “ii” no wordmark (coordenadas do viewBox). */\nexport const MOVIIE_EMBED_BRAND_LETTERMARK_STROKE_WIDTH = 3 as const\n","/**\n * Configura endpoints da API Moviie a partir de **variáveis de ambiente**\n * `EXPO_PUBLIC_MOVIIE_API_BASE_URL` e (raro) `EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL`.\n *\n * **Override é apenas para desenvolvimento local.** Apps em produção usam o\n * default `https://api.moviie.ai/v1`. Por isso este módulo:\n *\n * - Só aplica o override quando `__DEV__ === true` (Metro/Hermes dev mode);\n * - Não depende de `expo-constants` — usa só `process.env.*` que o Metro inlina\n * em build time para qualquer var `EXPO_PUBLIC_*`;\n * - Falha silenciosamente em produção (var inexistente → default do SDK).\n *\n * Vars relevantes (definidas em `.env.local` no consumer):\n * EXPO_PUBLIC_MOVIIE_API_BASE_URL=http://localhost:3000/api/v1\n * EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL=http://localhost:3000/telemetry/v1\n */\nimport { configureMoviieEndpoints } from '@moviie/player-sdk'\n\nimport {\n EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV,\n EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV,\n} from './constants'\n\nfunction normalize(raw: string | undefined): string | undefined {\n if (typeof raw !== 'string') return undefined\n const trimmed = raw.trim()\n return trimmed.length > 0 ? trimmed.replace(/\\/+$/, '') : undefined\n}\n\n// `__DEV__` é definido pelo bundler RN. Em web build (Vite/Next) cai pra `process.env.NODE_ENV`.\nconst devMode =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production'\n\nif (devMode) {\n const apiBaseUrl = normalize(process.env[EXPO_PUBLIC_MOVIIE_API_BASE_URL_ENV])\n const eventsBaseUrl = normalize(process.env[EXPO_PUBLIC_MOVIIE_EVENTS_BASE_URL_ENV])\n\n const opts: { apiBaseUrl?: string; eventsBaseUrl?: string } = {}\n if (apiBaseUrl != null) opts.apiBaseUrl = apiBaseUrl\n if (eventsBaseUrl != null) opts.eventsBaseUrl = eventsBaseUrl\n\n if (opts.apiBaseUrl != null || opts.eventsBaseUrl != null) {\n configureMoviieEndpoints(opts)\n }\n}\n","/**\n * Console warning idempotente por chave. Útil para dependências opcionais ausentes:\n * dispara uma única vez por sessão para a mesma chave, evitando ruído no console.\n *\n * Reusável para qualquer feature gated por dep opcional (cast, DRM custom,\n * analytics provider, etc.).\n */\n\nconst FIRED_KEYS = new Set<string>()\n\nexport function warnOnce(key: string, message: string): void {\n if (FIRED_KEYS.has(key)) {\n return\n }\n FIRED_KEYS.add(key)\n // eslint-disable-next-line no-console\n console.warn(message)\n}\n\n/** Limpa o set de chaves disparadas. Use apenas em testes. */\nexport function __resetWarnOnceForTests(): void {\n FIRED_KEYS.clear()\n}\n","import type { ViewerTokenStore } from '@moviie/player-sdk'\nimport { MemoryViewerTokenStore } from '@moviie/player-sdk'\n\nimport { warnOnce } from './lib/warn-once'\n\nexport const MOVIIE_VIEWER_TOKEN_SECURE_STORE_KEY = 'moviie_viewer_token_v1' as const\n\nconst SECURE_STORE_MISSING_WARNING =\n '[@moviie/player-expo] `expo-secure-store` não está instalado — viewer token será mantido apenas em memória (perde ao matar app). ' +\n 'Instala com `pnpm add expo-secure-store` se quiseres persistência entre sessões.'\n\ninterface StoredEnvelope {\n token: string\n expiresAt: number\n}\n\nfunction isStoredEnvelope(value: unknown): value is StoredEnvelope {\n if (!value || typeof value !== 'object') return false\n const v = value as Record<string, unknown>\n return typeof v.token === 'string' && typeof v.expiresAt === 'number'\n}\n\nexport class SecureStoreViewerTokenStore implements ViewerTokenStore {\n private readonly fallback: ViewerTokenStore\n private readonly storageKey: string\n\n constructor(options?: { fallback?: ViewerTokenStore; storageKey?: string }) {\n this.fallback = options?.fallback ?? new MemoryViewerTokenStore()\n this.storageKey = options?.storageKey ?? MOVIIE_VIEWER_TOKEN_SECURE_STORE_KEY\n }\n\n private async loadSecureStore(): Promise<typeof import('expo-secure-store') | null> {\n try {\n return await import('expo-secure-store')\n } catch {\n warnOnce('moviie:expo-secure-store-missing', SECURE_STORE_MISSING_WARNING)\n return null\n }\n }\n\n async get(): Promise<string | null> {\n const SecureStore = await this.loadSecureStore()\n if (!SecureStore) {\n return this.fallback.get()\n }\n try {\n const raw = await SecureStore.getItemAsync(this.storageKey)\n if (!raw) return null\n const parsed: unknown = JSON.parse(raw)\n if (!isStoredEnvelope(parsed)) {\n await SecureStore.deleteItemAsync(this.storageKey).catch(() => {})\n return null\n }\n if (parsed.expiresAt <= Date.now()) {\n await SecureStore.deleteItemAsync(this.storageKey).catch(() => {})\n return null\n }\n return parsed.token\n } catch {\n return this.fallback.get()\n }\n }\n\n async set(token: string, ttlSec: number): Promise<void> {\n const SecureStore = await this.loadSecureStore()\n const envelope: StoredEnvelope = {\n token,\n expiresAt: Date.now() + Math.max(0, ttlSec) * 1000,\n }\n if (!SecureStore) {\n await this.fallback.set(token, ttlSec)\n return\n }\n try {\n await SecureStore.setItemAsync(this.storageKey, JSON.stringify(envelope))\n } catch {\n await this.fallback.set(token, ttlSec)\n }\n }\n}\n","import * as Application from \"expo-application\"\n\nexport function readNativeApplicationId(): string | undefined {\n try {\n const id = Application.applicationId\n return id ?? undefined\n } catch {\n return undefined\n }\n}\n","import { Platform } from \"react-native\"\n\nimport type { MoviieClientInfo } from \"@moviie/player-sdk\"\n\nimport { readNativeApplicationId } from \"./native-application-id\"\n\nlet cached: MoviieClientInfo | null = null\n\nexport function buildPlatformClientInfo(sdkVersion: string): MoviieClientInfo {\n if (cached) {\n return cached\n }\n\n const os = Platform.OS\n const platform: MoviieClientInfo[\"platform\"] =\n os === \"ios\" ? \"ios\" : os === \"android\" ? \"android\" : \"web\"\n\n const bundleId =\n platform === \"web\" ? undefined : readNativeApplicationId()\n\n cached = {\n platform,\n bundleId,\n sdkVersion,\n }\n return cached\n}\n\nexport function resetPlatformClientInfoCache(): void {\n cached = null\n}\n","import {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\"\n\nimport {\n buildClientHeaders,\n MemoryViewerTokenStore,\n MoviieClient,\n type MoviieClientInfo,\n type ViewerTokenStore,\n} from \"@moviie/player-sdk\"\n\nimport { MOVIIE_PLAYER_EXPO_PKG_VERSION } from \"../constants\"\nimport { buildPlatformClientInfo } from \"../platform/platform-client-info\"\nimport { SecureStoreViewerTokenStore } from \"../secure-store-viewer-token-store\"\n\nexport interface MoviieContextValue {\n client: MoviieClient\n viewerTokenStore: ViewerTokenStore\n publishableKey: string | null\n clientInfo: MoviieClientInfo\n sdkVersion: string\n /** Headers reused by TelemetryClient (Bearer + X-Moviie-Client when aplicável) */\n telemetryHeaders: Record<string, string>\n}\n\nconst MoviieContext = createContext<MoviieContextValue | null>(null)\n\nlet fallbackContext: MoviieContextValue | null = null\n\nfunction getOrCreateFallbackContext(): MoviieContextValue {\n if (!fallbackContext) {\n const sdkVersion = MOVIIE_PLAYER_EXPO_PKG_VERSION\n const clientInfo = buildPlatformClientInfo(sdkVersion)\n const viewerTokenStore = new MemoryViewerTokenStore()\n const client = new MoviieClient({\n publishableKey: undefined,\n clientInfo,\n sdkVersion,\n })\n fallbackContext = {\n client,\n viewerTokenStore,\n publishableKey: null,\n clientInfo,\n sdkVersion,\n telemetryHeaders: buildClientHeaders({\n clientInfo,\n sdkVersion,\n }),\n }\n }\n return fallbackContext\n}\n\nexport function useMoviieContext(): MoviieContextValue {\n const ctx = useContext(MoviieContext)\n return ctx ?? getOrCreateFallbackContext()\n}\n\nexport function MoviieProvider({\n publishableKey,\n children,\n}: {\n publishableKey?: string | null\n children: ReactNode\n}) {\n const value = useMemo((): MoviieContextValue => {\n const sdkVersion = MOVIIE_PLAYER_EXPO_PKG_VERSION\n const clientInfo = buildPlatformClientInfo(sdkVersion)\n const trimmedKey = publishableKey?.trim()\n const viewerTokenStore = new SecureStoreViewerTokenStore()\n const client = new MoviieClient({\n publishableKey: trimmedKey || undefined,\n clientInfo,\n sdkVersion,\n })\n const telemetryHeaders = buildClientHeaders({\n publishableKey: trimmedKey || undefined,\n clientInfo,\n sdkVersion,\n })\n return {\n client,\n viewerTokenStore,\n publishableKey: trimmedKey ?? null,\n clientInfo,\n sdkVersion,\n telemetryHeaders,\n }\n }, [publishableKey])\n\n return (\n <MoviieContext.Provider value={value}>{children}</MoviieContext.Provider>\n )\n}\n"]}
package/dist/index.cjs CHANGED
@@ -46,7 +46,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
46
46
  });
47
47
 
48
48
  // src/constants.ts
49
- var MOVIIE_PLAYER_EXPO_PKG_VERSION = "0.4.0";
49
+ var MOVIIE_PLAYER_EXPO_PKG_VERSION = "0.5.1";
50
50
  var MOVIIE_PLAYBACK_MEMORY_CACHE_TTL_MS = 5 * 60 * 1e3;
51
51
  var MOVIIE_PLAYBACK_PROFILE = {
52
52
  VSL: "vsl",
@@ -983,18 +983,6 @@ var Stop = RNSvg.Stop;
983
983
  var AnimatedView = reactNative.Animated.View;
984
984
  var ReanimatedView = AnimatedReanimated__default.default.View;
985
985
 
986
- // src/lib/moviie-telemetry-callbacks.ts
987
- function safeInvokeMoviieTelemetry(callback, ...args) {
988
- if (callback == null) {
989
- return;
990
- }
991
- try {
992
- callback(...args);
993
- } catch (err) {
994
- console.warn("[@moviie/player-expo] telemetry callback threw \u2014 ignorado", err);
995
- }
996
- }
997
-
998
986
  // src/lib/moviie-shell-tokens.ts
999
987
  var MOVIIE_SHELL_BACKGROUND_HEX = "#0a0a0a";
1000
988
  var MOVIIE_SHELL_RADIAL_INNER_HEX = "#1a1a1a";
@@ -3479,25 +3467,9 @@ var MoviieVideoImpl = React.forwardRef(
3479
3467
  retry,
3480
3468
  castAdapter: castAdapterProp,
3481
3469
  cast,
3482
- onTelemetryError,
3483
- onTelemetryEvent,
3484
3470
  ...videoRest
3485
3471
  } = props;
3486
3472
  const castAdapter = castAdapterProp ?? getRegisteredCastAdapter();
3487
- const lastReportedErrorRef = React.useRef(null);
3488
- React.useEffect(() => {
3489
- if (error == null) {
3490
- lastReportedErrorRef.current = null;
3491
- return;
3492
- }
3493
- if (lastReportedErrorRef.current === error) {
3494
- return;
3495
- }
3496
- lastReportedErrorRef.current = error;
3497
- safeInvokeMoviieTelemetry(onTelemetryError, error, {
3498
- phase: "playback_fetch"
3499
- });
3500
- }, [error, onTelemetryError]);
3501
3473
  const useMoviieChrome = !native;
3502
3474
  const shellState = playback != null ? "ready" : error != null ? "error" : "loading";
3503
3475
  const loadingOpacity = AnimatedReanimated.useSharedValue(shellState === "loading" ? 1 : 0);