@vyonio/player 0.0.0-stage → 0.2.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/CHANGELOG.md +38 -0
- package/README.md +346 -2
- package/THIRD_PARTY_NOTICES.txt +682 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +38 -0
- package/dist/plyr-icons.svg +1 -0
- package/dist/style.css +2 -0
- package/package.json +40 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1 — 2026-10-15
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Prefer standard or WebKit element fullscreen when available, then native video
|
|
8
|
+
fullscreen on supported iOS video elements, retaining Plyr's CSS fallback.
|
|
9
|
+
- Request fullscreen synchronously from an explicit user action. Opening,
|
|
10
|
+
metadata, playing and autoplay do not enter fullscreen automatically.
|
|
11
|
+
- Recover from unsupported or rejected fullscreen entry; restore inline controls
|
|
12
|
+
on exit and clean up listeners and fullscreen state on destroy/remount.
|
|
13
|
+
Delayed WebKit exit and element entry completing after teardown are covered.
|
|
14
|
+
- Respect disabled or omitted fullscreen controls, including keyboard and
|
|
15
|
+
double-click actions.
|
|
16
|
+
- Remove the unconditional 192px mount minimum. Preserve explicit host sizing
|
|
17
|
+
even when SDK CSS loads last, intrinsic sizing for width-only hosts, source
|
|
18
|
+
aspect ratios, letterboxing, and responsive controls without remounting.
|
|
19
|
+
|
|
20
|
+
### Validation and limitations
|
|
21
|
+
|
|
22
|
+
- 196 unit/release-script tests and 36 offline browser regression tests passed.
|
|
23
|
+
Browser tests use real Plyr and the built SDK stylesheet in headless Chrome;
|
|
24
|
+
fullscreen capability APIs are simulated. All five requested viewport widths
|
|
25
|
+
(320, 375, 390, 844 and 1400px), rotation, and lifecycle races are covered.
|
|
26
|
+
- Build and independent tarball consumer installation/type-check/build passed.
|
|
27
|
+
- Physical iPhone fullscreen with a supported protected video is **not verified**.
|
|
28
|
+
Apple iPhone Simulator was not used. This release does not claim FairPlay/DRM
|
|
29
|
+
device certification. Native fullscreen uses system controls and cannot render
|
|
30
|
+
HTML badges, the popularity histogram or custom HTML overlays.
|
|
31
|
+
|
|
32
|
+
### Consumer migration
|
|
33
|
+
|
|
34
|
+
Upgrade the locked `@vyonio/player` dependency to `0.2.1`. Remove the Rails
|
|
35
|
+
`nativeVideoFullscreen()` click-interception helper and its lifecycle wiring.
|
|
36
|
+
After verifying sizing with the released package, remove the SDK-specific
|
|
37
|
+
`min-height: 0` workaround. Keep application container sizing, modal scrolling
|
|
38
|
+
and course-navigation fixes.
|
package/README.md
CHANGED
|
@@ -1,3 +1,347 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @vyonio/player
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shaka Player engine with Plyr chrome for Vyonio DRM video playback. Plyr styles and the control-icon SVG sprite ship with the package, so playback does not depend on the Plyr CDN or require it in the host's Content Security Policy. If Plyr fails to initialize, the player falls back to native `<video controls>`.
|
|
4
|
+
|
|
5
|
+
> **Release availability:** source checkouts can be ahead of npm. Check available
|
|
6
|
+
> versions with `npm view @vyonio/player versions`. For an unpublished checkout,
|
|
7
|
+
> use `npm run verify:package` or a local `npm pack` tarball. Customer setup is in
|
|
8
|
+
> the [public npm guide](https://developers.vyonio.com/npm-player/) and
|
|
9
|
+
> [shared backend guide](https://developers.vyonio.com/protected-playback/).
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @vyonio/player
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The ESM package bundles Shaka and Plyr and exports TypeScript declarations.
|
|
18
|
+
Import `@vyonio/player/style.css` once in your application. The default API is
|
|
19
|
+
`https://api.vyonio.com`; set `apiBase` only when using another environment.
|
|
20
|
+
|
|
21
|
+
For a clean repository checkout, first run `npm ci --prefix packages/player`,
|
|
22
|
+
then `npm ci --prefix <app>` for each app you use (`client`, `course`, `player`,
|
|
23
|
+
`dash`). App build and dev scripts build the shared package before starting;
|
|
24
|
+
they do not install dependencies. Run `npm --prefix packages/player run verify:package` to pack, install, type-check, and build an independent consumer.
|
|
25
|
+
`npm pack` runs the library build through `prepack`. Local verification prepares
|
|
26
|
+
a release artifact; publishing npm and hosted artifacts is a separate step.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Public video
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
import { VyonioPlayer } from '@vyonio/player';
|
|
34
|
+
import '@vyonio/player/style.css';
|
|
35
|
+
|
|
36
|
+
const { player, destroy } = await VyonioPlayer.mount(element, {
|
|
37
|
+
apiBase: 'http://localhost:3000',
|
|
38
|
+
embedUuid: '550e8400-e29b-41d4-a716-446655440000',
|
|
39
|
+
autoplay: false,
|
|
40
|
+
muted: false,
|
|
41
|
+
loop: false,
|
|
42
|
+
controls: true,
|
|
43
|
+
controlItems: ['play-large', 'play', 'progress', 'current-time', 'fullscreen'],
|
|
44
|
+
settingsItems: ['quality'],
|
|
45
|
+
language: 'cs',
|
|
46
|
+
accentColor: '#7c3aed',
|
|
47
|
+
badge: {
|
|
48
|
+
text: 'AI-assisted',
|
|
49
|
+
position: 'top-right',
|
|
50
|
+
style: 'accent'
|
|
51
|
+
},
|
|
52
|
+
startSeconds: 0
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The optional playback settings are intended for hosted embeds as well as
|
|
57
|
+
direct integrations. Browsers generally require `muted: true` when autoplay is
|
|
58
|
+
enabled. A rejected autoplay attempt leaves the player ready for manual play.
|
|
59
|
+
`controlItems` accepts Plyr control names and is ignored when `controls` is
|
|
60
|
+
false. `settingsItems` accepts `quality` and `speed`; it defaults to
|
|
61
|
+
`['quality']`, so playback speed is opt-in. An empty array removes the settings
|
|
62
|
+
menu, and unavailable quality choices hide automatically. `language` accepts
|
|
63
|
+
`en` and `cs` and defaults to English. Unsupported languages fall back to
|
|
64
|
+
English. `accentColor` accepts only a six-digit hex color. Badge text is rendered
|
|
65
|
+
as plain text inside Plyr's fullscreen container and is limited to 64
|
|
66
|
+
characters; positions are the four corners and styles are `dark`, `light`, or
|
|
67
|
+
`accent`.
|
|
68
|
+
|
|
69
|
+
### Fullscreen and responsive hosts
|
|
70
|
+
|
|
71
|
+
Fullscreen uses element fullscreen when the mounted video's document supports
|
|
72
|
+
it, then native video fullscreen (`fullscreen.iosNative`) when available, and
|
|
73
|
+
Plyr's full-window CSS fallback otherwise. Entry happens only on an explicit
|
|
74
|
+
fullscreen action; mounting, metadata, playing and autoplay do not request it.
|
|
75
|
+
If native entry fails, the existing CSS fallback remains usable. Exiting keeps
|
|
76
|
+
inline playback and controls available. `controls: false` or a `controlItems`
|
|
77
|
+
list without `fullscreen` also disables keyboard and double-click entry.
|
|
78
|
+
Consumers do not need a click interceptor on Plyr's private DOM selectors.
|
|
79
|
+
|
|
80
|
+
Native iPhone fullscreen uses system video controls. HTML badges, the popularity
|
|
81
|
+
histogram and other HTML overlays are not rendered in that system view; custom
|
|
82
|
+
quality/settings UI is available again after returning inline. Do not depend on
|
|
83
|
+
HTML badges for mandatory watermarking. See [Plyr's fullscreen options](https://github.com/sampotts/plyr#options)
|
|
84
|
+
and [Apple's native video API](https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1633500-webkitenterfullscreen).
|
|
85
|
+
|
|
86
|
+
The mount fills a sized host, including heights below 192px, with no minimum
|
|
87
|
+
height override required. Host rules win over SDK size defaults even when the
|
|
88
|
+
SDK stylesheet is loaded last. A width-only host uses the video's intrinsic
|
|
89
|
+
aspect ratio once metadata is available (16:9 before that). Media uses
|
|
90
|
+
`object-fit: contain`, so differing host/media ratios produce intentional
|
|
91
|
+
letterboxing. Resizing and orientation changes do not require a remount.
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
/* Choose a host size appropriate to your layout. */
|
|
95
|
+
.video-slot {
|
|
96
|
+
width: 100%;
|
|
97
|
+
aspect-ratio: 16 / 9;
|
|
98
|
+
border-radius: 0.75rem;
|
|
99
|
+
overflow: hidden;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Verify fullscreen and sizing changes
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
# From packages/player, with Node 22.12+ and installed dependencies:
|
|
107
|
+
npm test
|
|
108
|
+
# Uses installed Google Chrome. To provision it when absent:
|
|
109
|
+
# npx playwright install chrome
|
|
110
|
+
npm run test:browser
|
|
111
|
+
npm run verify:package
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Browser regressions build and load the shipped `dist/style.css` after host CSS
|
|
115
|
+
with real Plyr markup. They cover direct/nested 16:9 hosts at viewport widths
|
|
116
|
+
320, 375, 390, 844 and 1400px, explicit 120px height, width-only hosts, metadata
|
|
117
|
+
aspect-ratio changes, portrait/landscape resizing, visible usable controls,
|
|
118
|
+
capability selection, synchronous entry, fallback, exit and teardown races.
|
|
119
|
+
They block non-local requests and need no live token/media/DRM/analytics/payment
|
|
120
|
+
services. Browser fullscreen APIs are simulated; desktop mobile emulation does
|
|
121
|
+
not establish that native iPhone fullscreen or protected playback works.
|
|
122
|
+
|
|
123
|
+
Device acceptance remains outstanding: verify on a **physical iPhone** using a supported
|
|
124
|
+
protected video: open/play stays inline; tapping fullscreen opens system video
|
|
125
|
+
fullscreen; exit restores inline video and working controls; repeat entry,
|
|
126
|
+
rotation, closing while fullscreen, source switching and remounting work.
|
|
127
|
+
Record device/iOS/Safari versions and the protected asset/DRM mode without
|
|
128
|
+
recording secrets. Physical iPhone verification has **not** been completed in
|
|
129
|
+
this change.
|
|
130
|
+
|
|
131
|
+
See the shipped [changelog](./CHANGELOG.md) for the 0.2.1 fixes and known
|
|
132
|
+
verification limits. The 0.2.1 patch follows the [repository release procedure](https://gitlab.com/buildio/playground/vyonio.com/-/blob/main/docs/player-release.md);
|
|
133
|
+
0.2.0 remains immutable. Package version files and the `player-v0.2.1` tag are
|
|
134
|
+
recorded by that procedure only after publication and registry verification.
|
|
135
|
+
|
|
136
|
+
After upgrading the Rails consumer's locked dependency to 0.2.1, remove
|
|
137
|
+
`nativeVideoFullscreen()` and its lifecycle wiring, then remove its SDK-specific
|
|
138
|
+
`min-height: 0` workaround after sizing is verified against the released package.
|
|
139
|
+
Keep normal container sizing, modal scrolling and course-navigation fixes in
|
|
140
|
+
the application.
|
|
141
|
+
|
|
142
|
+
### Popularity histogram
|
|
143
|
+
|
|
144
|
+
Pass equal-duration popularity buckets to render a YouTube-like engagement
|
|
145
|
+
curve above the seek bar (white top stroke, fade-to-transparent fill). The
|
|
146
|
+
overlay is non-interactive and only appears while the progress control is
|
|
147
|
+
hovered or scrubbed:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
await VyonioPlayer.mount(element, {
|
|
151
|
+
apiBase: 'http://localhost:3000',
|
|
152
|
+
embedUuid: '550e8400-e29b-41d4-a716-446655440000',
|
|
153
|
+
popularityHistogram: {
|
|
154
|
+
buckets: [12, 18, 31, 24, 15]
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Each bucket spans an equal portion of the video duration, and heights are
|
|
160
|
+
normalized against the largest value. The player also accepts the same array
|
|
161
|
+
from `popularity_histogram.buckets` in the playback descriptor when a backend
|
|
162
|
+
provides it. Explicit mount-option buckets take precedence. The current Vyonio
|
|
163
|
+
Platform descriptor does not supply popularity buckets; aggregation and API
|
|
164
|
+
delivery are a separate backend feature.
|
|
165
|
+
|
|
166
|
+
HTML badges stay visible in normal Plyr fullscreen, but cannot be guaranteed in
|
|
167
|
+
native video fallback, Picture in Picture, AirPlay, casting, or downloaded
|
|
168
|
+
media. Use a burned-in watermark for compliance-critical or tamper-resistant
|
|
169
|
+
marking.
|
|
170
|
+
|
|
171
|
+
Fetches the video descriptor from `{apiBase}/v1/embed/{embedUuid}`, attaches a `<video>` element with Plyr controls (or native controls on Plyr failure), configures Widevine DRM, and loads the DASH manifest. Safari/FairPlay is scaffolded and throws until Apple FPS credentials are deployed.
|
|
172
|
+
|
|
173
|
+
The returned handle also exposes media controls used by the hosted iframe API:
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
const handle = await VyonioPlayer.mount(element, options);
|
|
177
|
+
|
|
178
|
+
await handle.play();
|
|
179
|
+
handle.pause();
|
|
180
|
+
handle.seek(30);
|
|
181
|
+
handle.setMuted(true);
|
|
182
|
+
console.log(handle.getState());
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`seek(seconds)` accepts a nonnegative finite number and clamps it to the known
|
|
186
|
+
duration. `getState()` returns `currentTime`, `duration`, `paused`, `ended`, and
|
|
187
|
+
`muted`. The underlying `HTMLVideoElement` is available as `mediaElement` for
|
|
188
|
+
advanced event handling.
|
|
189
|
+
|
|
190
|
+
If the descriptor includes a `telemetry` endpoint and signed context, the
|
|
191
|
+
player automatically emits batched `start`, `heartbeat`, `pause`, `seek`,
|
|
192
|
+
`end`, `leave`, and `error` events. Telemetry is best-effort: failures and an
|
|
193
|
+
absent telemetry descriptor never interrupt playback. Pipeline credentials are
|
|
194
|
+
held by the Platform API and are never exposed to the browser.
|
|
195
|
+
|
|
196
|
+
Every mounted player uses a fresh random session UUID. Heartbeat, pause, end,
|
|
197
|
+
and leave events close continuous watched spans with millisecond start/end,
|
|
198
|
+
duration, watched time, buffering time, and playback rate. A seek closes the
|
|
199
|
+
preceding span and records only its origin and destination, so skipped content
|
|
200
|
+
is not counted as watched. Telemetry contains no user/member ID, stable device
|
|
201
|
+
ID, fingerprint, page/referrer URL, or cross-session cookie.
|
|
202
|
+
|
|
203
|
+
### Protected video (playback JWT)
|
|
204
|
+
|
|
205
|
+
For a same-origin customer endpoint:
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
const handle = await VyonioPlayer.mount(element, {
|
|
209
|
+
embedUuid: 'your-embed-uuid',
|
|
210
|
+
tokenEndpoint: '/api/playback-token',
|
|
211
|
+
tokenHeaders: { 'X-CSRF-Token': csrfToken }
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The endpoint receives `POST` JSON `{ embedUuid }` with same-origin credentials
|
|
216
|
+
and must authenticate the viewer and recheck entitlement on every request.
|
|
217
|
+
Return JSON `{ token, expires_in: 600 }` with `Cache-Control: no-store`.
|
|
218
|
+
Keep the Vyonio API key only on your server. Customers never need Vyonio's JWT signing secret.
|
|
219
|
+
`tokenEndpoint` and `getPlaybackToken` are mutually exclusive. Endpoint URLs
|
|
220
|
+
must be same-origin; `tokenHeaders` cannot include Authorization. Token
|
|
221
|
+
acquisition times out after 15 seconds and rejects with `PlaybackTokenError`
|
|
222
|
+
(`PLAYBACK_TOKEN_FAILED` or `PLAYBACK_TOKEN_TIMEOUT`).
|
|
223
|
+
|
|
224
|
+
Pass `tokenEndpoint` or `getPlaybackToken` to attach a short-lived playback JWT before the descriptor fetch. The player:
|
|
225
|
+
|
|
226
|
+
- Sends `Authorization: Bearer <token>` on the descriptor request and all Shaka network requests (via a request filter)
|
|
227
|
+
- Appends `access_token=<token>` to the DASH manifest URL (for AirPlay / devices that cannot send headers)
|
|
228
|
+
- Replaces `access_token` on subsequent platform manifest, segment, and license request URLs after each token refresh
|
|
229
|
+
- Schedules automatic refresh from the JWT `exp` claim, **120 seconds before expiry**
|
|
230
|
+
- Starts refresh scheduling only after the manifest loads successfully
|
|
231
|
+
- On refresh failure, marks the mount and video elements with `data-state="error"`, emits a `vyonio-player-error` event from the mount element, calls optional `onError`, then destroys the player and removes the video element
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
const { player, destroy } = await VyonioPlayer.mount(element, {
|
|
235
|
+
apiBase: 'http://localhost:3000',
|
|
236
|
+
embedUuid: '550e8400-e29b-41d4-a716-446655440000',
|
|
237
|
+
onError: ({ code, message, error }) => {
|
|
238
|
+
// code is PLAYBACK_AUTH_REFRESH_FAILED for token refresh failures.
|
|
239
|
+
showPlaybackError(message);
|
|
240
|
+
},
|
|
241
|
+
getPlaybackToken: async () => {
|
|
242
|
+
const res = await fetch('/api/playback-token', {
|
|
243
|
+
method: 'POST',
|
|
244
|
+
credentials: 'same-origin',
|
|
245
|
+
cache: 'no-store',
|
|
246
|
+
redirect: 'error',
|
|
247
|
+
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken },
|
|
248
|
+
body: JSON.stringify({ embedUuid: '550e8400-e29b-41d4-a716-446655440000' })
|
|
249
|
+
});
|
|
250
|
+
if (!res.ok) throw new Error(`Token mint failed: ${res.status}`);
|
|
251
|
+
const { token } = await res.json();
|
|
252
|
+
return token;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The `vyonio-player-error` event is a `CustomEvent` with the same `{ code, message, error }` object in `event.detail`. This lets applications surface an authentication or entitlement error even when they do not provide `onError`.
|
|
258
|
+
|
|
259
|
+
When both authentication options are omitted, behavior matches the public path (no Bearer header, no manifest query param, no refresh timer).
|
|
260
|
+
|
|
261
|
+
## Playback descriptor: captions and chapters
|
|
262
|
+
|
|
263
|
+
The embed descriptor (`GET {apiBase}/v1/embed/{embedUuid}`) may include:
|
|
264
|
+
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"captions": [
|
|
268
|
+
{
|
|
269
|
+
"language": "cs",
|
|
270
|
+
"label": "Čeština",
|
|
271
|
+
"kind": "subtitles",
|
|
272
|
+
"vtt_url": "https://media.example/caption_tracks/1/vtt",
|
|
273
|
+
"default": true
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
"chapters": [
|
|
277
|
+
{ "title": "Intro", "start_seconds": 0 },
|
|
278
|
+
{ "title": "Main", "start_seconds": 42 }
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
- **`captions`**: optional array of sidecar WebVTT tracks. Each entry supplies `language`, `label`, `kind` (`subtitles` or `captions`), authenticated `vtt_url`, and optional `default` (boolean). When `getPlaybackToken` is used, the player appends `access_token` to each `vtt_url` the same way it does for the DASH manifest.
|
|
284
|
+
- **`chapters`**: optional array of chapter cues with `title` and `start_seconds`. The player builds an in-memory chapters WebVTT track for Plyr's chapter menu; cue end times are the next chapter start or video duration.
|
|
285
|
+
|
|
286
|
+
When either field is absent or empty, the corresponding Plyr control stays idle.
|
|
287
|
+
|
|
288
|
+
## Tests
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
npm test
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## React and SSR
|
|
295
|
+
|
|
296
|
+
The browser engine uses DOM globals. Import `@vyonio/player` dynamically inside
|
|
297
|
+
a client effect; do not import the engine in a server-evaluated module. Import
|
|
298
|
+
the CSS once through your framework's supported global CSS entry. Cancel stale
|
|
299
|
+
mounts, destroy their late handles, and call `destroy()` on cleanup. The
|
|
300
|
+
[public npm guide](https://developers.vyonio.com/npm-player/#react-and-server-rendering)
|
|
301
|
+
contains the complete lifecycle example.
|
|
302
|
+
|
|
303
|
+
See the [runnable customer example](../../examples/protected-playback/README.md)
|
|
304
|
+
for the same-origin `{ embedUuid }` request, CSRF `tokenHeaders`, server-only key,
|
|
305
|
+
current entitlement checks, and Node/PHP host replacement points. Its login is
|
|
306
|
+
local demonstration authentication, not a production identity system. Protected
|
|
307
|
+
access can be used with clear or DRM media; this package preserves your existing
|
|
308
|
+
account DRM configuration and does not provision FairPlay.
|
|
309
|
+
|
|
310
|
+
## Maintainer releases
|
|
311
|
+
|
|
312
|
+
From the repository root, use Node 22.12+ and your own npm account with Vyonio
|
|
313
|
+
publish access. Commit package changes first, leave the Git index empty, and sign
|
|
314
|
+
in once with `npm login`. Use a named branch with Git `user.name`/`user.email`
|
|
315
|
+
configured and no merge/rebase in progress.
|
|
316
|
+
|
|
317
|
+
```sh
|
|
318
|
+
# First publication of the existing package version:
|
|
319
|
+
npm --prefix packages/player run release -- current --dry-run
|
|
320
|
+
npm --prefix packages/player run release -- current
|
|
321
|
+
|
|
322
|
+
# Later bug-fix release:
|
|
323
|
+
npm --prefix packages/player run release -- patch --dry-run
|
|
324
|
+
npm --prefix packages/player run release -- patch
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Choose `minor` for a feature release or `major` for breaking changes. These commands
|
|
328
|
+
accept stable versions only; prereleases need a separately reviewed release.
|
|
329
|
+
The command builds a temporary copy of tracked package source, installs locked
|
|
330
|
+
dependencies, runs all package tests, and verifies the tarball in an independent
|
|
331
|
+
TypeScript/browser consumer. A real release asks for confirmation and uses npm's
|
|
332
|
+
normal login/2FA flow. Only that verified tarball is published. It then checks
|
|
333
|
+
registry integrity and installs the exact version from npm.
|
|
334
|
+
|
|
335
|
+
Dry runs, cancellation and failed preparation leave your working version files
|
|
336
|
+
unchanged, and create no commits or tags. After publication and registry
|
|
337
|
+
installation verification, a bumped release commits only the manifest and
|
|
338
|
+
lockfile, then creates an annotated `player-vX.Y.Z` tag on that exact commit.
|
|
339
|
+
`current` tags the existing matching-version commit without adding an empty
|
|
340
|
+
commit. The annotation records the npm artifact integrity. Existing local/origin
|
|
341
|
+
tags are never overwritten. Unrelated unstaged work stays outside the release
|
|
342
|
+
commit; any staged work blocks release.
|
|
343
|
+
|
|
344
|
+
Review the local release commit and tag, then push them through your normal Git
|
|
345
|
+
workflow. The command does not push tags or deploy hosted/docs assets. Read the
|
|
346
|
+
[release runbook](../../docs/player-release.md) for first-release setup, Git/tag
|
|
347
|
+
recovery and post-release documentation.
|