@torrent-tv/proxy 2.73.1 → 2.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +1447 -1437
  2. package/CLAUDE.md +165 -160
  3. package/docs/container-architecture.md +192 -184
  4. package/package.json +1 -1
  5. package/routes/api/subtitles/get.js +205 -205
  6. package/services/container/Container.js +354 -135
  7. package/services/container/MatroskaContainer.js +1155 -516
  8. package/services/container/Mp4Container.js +858 -392
  9. package/services/container/SubtitleFileContainer.js +323 -261
  10. package/services/controllers/SubtitleController.js +128 -127
  11. package/services/delivery-probe.js +64 -6
  12. package/services/hls-session-manager.js +32 -35
  13. package/services/language-detect.js +174 -228
  14. package/services/playback-planner.js +747 -747
  15. package/services/produced-index.js +300 -0
  16. package/services/torrent-worker/subtitle-cues.js +582 -633
  17. package/services/tracks/TextSubtitleTrack.js +287 -47
  18. package/services/tracks/index.js +14 -14
  19. package/test/delivery-probe.test.js +67 -0
  20. package/test/matroska-blocks.test.js +0 -0
  21. package/test/mp4-subtitles.test.js +173 -127
  22. package/test/produced-index.test.js +188 -0
  23. package/test/subtitle-cue-framing.test.js +200 -202
  24. package/test/subtitle-cue-walk.test.js +369 -0
  25. package/test/subtitle-defaults.test.js +97 -97
  26. package/test/subtitle-language.test.js +252 -252
  27. package/test/subtitle-track-numbering.test.js +370 -370
  28. package/services/container-index/matroska-blocks.js +0 -202
  29. package/services/container-index/matroska-subtitles.js +0 -372
  30. package/services/container-index/mp4-subtitles.js +0 -404
  31. package/services/subtitle-convert.js +0 -144
  32. package/services/subtitle-defaults.js +0 -157
  33. package/services/tracks/subtitle-markup.js +0 -104
package/CLAUDE.md CHANGED
@@ -1,160 +1,165 @@
1
- # proxy — @torrent-tv/proxy (WebTorrent + ffmpeg)
2
-
3
- Downloads a torrent and streams the chosen file to the browser, transcoding to
4
- HLS only when needed. See the parent `../CLAUDE.md` for the overall architecture
5
- and release process.
6
-
7
- ## Deployment-agnostic — important
8
-
9
- The HA addon is only ONE way to run this; bare npm and Docker are planned. Keep
10
- all code free of Home-Assistant assumptions. Anything host-specific (GPU
11
- devices, ffmpeg build, CLI flags) belongs in the `ha-addon` layer. Hardware
12
- detection must probe at runtime and fall back gracefully; do not assume a
13
- Linux-only host (e.g. POSIX-only signals must degrade elsewhere).
14
-
15
- ## Layout
16
-
17
- - `bin/cli.js` — CLI entry; resolves `ffmpegBin` (uses `--ffmpeg-bin` if given,
18
- else bundled ffmpeg-static, else PATH `ffmpeg`).
19
- - `server.js` — Fastify setup; detects the video encoder at startup
20
- (`detectVideoEncoder`) and passes it to `HlsSessionManager`.
21
- - `routes/<path>/<method>.js` — same convention as the server repo.
22
- - `routes/stream/get.js` — byte-range torrent file streaming (HTTP 206).
23
- - `routes/api/playback-plan/post.js` — codec/container/duration probe result.
24
- - `routes/transcode/session-file/get.js` — serves HLS playlist/segments;
25
- long-polls while a segment is being produced, returns retryable 503 (never
26
- 202 — hls.js can't consume it).
27
- - `services/`:
28
- - `demand/` — what anybody wants, in BYTES: `Window` (claimant, file, byte
29
- range, urgency), `Urgency` (BLOCKED / NEAR / AHEAD / TAIL / BEHIND),
30
- `DemandRegister` (live windows by claimant), `pieces.js` (the one place
31
- bytes become piece numbers). No WebTorrent, no piece store, no pieces.
32
- - `download/` — `SwarmSelection`, the ONLY thing that calls `select`,
33
- `deselect` or `critical`, and `registry.js`, which holds one per torrent and
34
- owns the cross-torrent rule that withholds the speculative levels while
35
- anything urgent is missing anywhere. See `docs/download-architecture.md`.
36
- - `container/` — domain layer: `Container` (abstract, RFC 9559 / ISO 14496-12),
37
- `MatroskaContainer` / `Mp4Container` / `AviContainer`, `ContainerFactory`
38
- (sniff 16 bytes → precise subclass). See `docs/container-architecture.md`.
39
- - `tracks/` — domain layer: `ContainerTrack` (base: TrackNumber, declaredIndex,
40
- language/BCP47, isEnabled/isDefault) → `VideoTrack` / `AudioTrack` /
41
- `SubtitleTrack` → `TextSubtitleTrack` / `ImageSubtitleTrack`,
42
- `ExternalSubtitleFile`. Spec-accurate flags (FlagForced only on subtitles per
43
- RFC 9559 §5.1.4.1, FlagOriginal/Commentary only on audio, tkhd
44
- track_enabled / alternate_group, elng BCP47).
45
- - `orchestrators/` — application layer: `ContainerOrchestrator` (detect + per-file
46
- cache, `getTracks`/`getKeyframeIndex`), `SubtitleOrchestrator` (wraps
47
- `torrent-worker/subtitle-cues.js` cluster walk + `Container` tracks, warm/push).
48
- - `controllers/` — interface layer: `PlaybackController` / `SubtitleController`
49
- (thin adapters over orchestrators; routes depend on controllers, not services).
50
- `routes/*` are now thin HTTP translators.
51
- - `container-index/` legacy readers (ebml-reader, matroska/mp4/avi keyframe and
52
- subtitle tables) used internally by `container/*`, deprecated as direct import.
53
- - `docs/download-architecture.md`the two axes of downloading: what is
54
- wanted (`demand/`) against what the swarm is told (`download/`), why urgency
55
- is not a number given to the library, and why the speculative levels are
56
- withdrawn rather than lowered.
57
- - `docs/logs.md` where to find logs (HA `docker logs` + `/data/proxy.log`, DO
58
- `infra-server-1` with forwarded frontend `POST /api/client-logs`). Browser
59
- console not needed.
60
- - `playback-planner.js` single ffmpeg probe returns audioCodec, videoCodec,
61
- container, durationSeconds. `mode` is advisory; the browser decides.
62
- - `hls-session-manager.js` — one ffmpeg per (source, file, settings). Serves a
63
- synthetic full-duration VOD playlist; produces segments on demand; restarts
64
- ffmpeg at the requested segment for server-side seeking. Short idle TTL.
65
- Uses the detected `videoEncoder` for video re-encode (copy otherwise).
66
- - `hwaccel.js` detect best H.264 encoder (NVENC/QSV/VAAPI/V4L2M2M) with a
67
- STRICT startup test: encode `testsrc2` through the real HLS pipeline, then
68
- verify each segment decodes independently (catches non-IDR/corrupted hw
69
- output). Falls back to software libx264. Runtime fallback to software if a
70
- hw encode later fails. v4l2m2m is gated by this test (fails on HA Yellow).
71
- - `data-channel-handler.js` — forwards WebRTC data-channel requests to the
72
- local HTTP server (loopback), so the same routes serve both transports.
73
-
74
- ## Gotchas
75
-
76
- - Do NOT use `-hls_playlist_type event` — it breaks duration/seek. VOD only.
77
- - A transitive dep (`ip-set`, via webtorrent) ships a hostile
78
- `preinstall: npx only-allow pnpm` that breaks `npm install`. The addon works
79
- around it with `--ignore-scripts` + a targeted rebuild of `node-datachannel`;
80
- if you ever change install flow, keep that in mind.
81
-
82
- ## Planned: public reachability (remote access)
83
-
84
- Decided direction full plan in the parent `../CLAUDE.md`. Proxy-side pieces:
85
-
86
- - **Auto port mapping** — IMPLEMENTED (`services/port-mapper.js`, changelog
87
- 2.9.16). UPnP IGD / NAT-PMP via `@silentbot1/nat-api` (now a direct dep; the
88
- same lib WebTorrent uses for the torrent port). Maps TCP 9090 with a 2 h
89
- auto-renewed lease, removed on shutdown (lease expiry covers hard kills).
90
- Best-effort + start/stop timeouts; `--no-port-mapping` opts out;
91
- `getMappedEndpoint()` exposes the external endpoint. NOT yet done: mapping the
92
- **UDP** port WebRTC actually uses (it binds ephemeral UDP ports, so this TCP
93
- mapping does not yet help WebRTC roadmap step 3 in the parent CLAUDE.md).
94
- Also pending (next iteration): a success log line in `port-mapper.js` `stop()`
95
- (`removed mapping for TCP <port>`) today stop() only logs on failure, so a
96
- clean unmap on shutdown is silent.
97
- - **Report endpoint to server** DONE (proxy 2.9.17). The mapped endpoint
98
- is sent over the tunnel (`tunnel-client.sendEndpoint` → `proxy-endpoint`) on
99
- mapping success and on every tunnel (re)connect; the server dial-back-verifies
100
- reachability (server 0.8.22, roadmap step 2).
101
- - **HTTPS listener**: serve the existing routes over TLS with a per-proxy
102
- certificate delivered by the server through the tunnel (persist cert+key
103
- locally; ~90-day renewals are pushed the same way). Add CORS headers for the
104
- web-app origin so hls.js / `<video>` can fetch cross-origin.
105
- - Plain HTTPS becomes the preferred video transport; WebRTC data channel stays
106
- as fallback for hosts where no port could be opened.
107
- - **Later roadmap steps** (single staged roadmap in parent `../CLAUDE.md`,
108
- WebRTC-first ordering): step 3 map the WebRTC UDP port (fixed
109
- `portRangeBegin`/`End` + UPnP-map UDP); step 4 birthday-paradox port
110
- prediction (open ~256 UDP sockets, inject predicted-port ICE candidates) for
111
- symmetric NAT; step 5 IPv6-first (audit the candidate filter — do not drop
112
- *global* v6) + STUN NAT pre-classification reported to the registry; then
113
- the DNS+TLS path (steps 6–7); step 8 relay-then-upgrade (deferred).
114
- - Future: ed25519 proxy identity (sign announcements), BEP 44 endpoint
115
- announcements via the `bittorrent-dht` already bundled with WebTorrent.
116
-
117
- All of this must stay deployment-agnostic (HA addon, bare npm, Docker).
118
-
119
- ## Disk hygiene (open item torrent data is NOT cleaned up today)
120
-
121
- HLS segments are handled (`hls-session-manager.js`: idle TTL, `disposeSession`,
122
- `disposeAll`). Torrent data is **partially** handled: shutdown cleanup is done
123
- (`TorrentPool.destroyAll()` with `destroyStore: true`, wired into the `onClose`
124
- hook proxy 2.9.15), but `deselect()` only stops further download and nothing
125
- removes a torrent's data **while the proxy keeps running**, nor sweeps orphans
126
- left by a previous hard kill at startup.
127
-
128
- Level 1 — remaining: `client.remove(torrent, { destroyStore: true })` on last-
129
- file refcount 0 + idle TTL (mirror the HLS session model); startup sweep of
130
- orphaned store dirs under `os.tmpdir()`; global disk cap with LRU eviction of
131
- whole torrents. (Shutdown teardown done.)
132
- Level 2 (research): sliding-window chunk store. Full rationale in the parent
133
- `../CLAUDE.md` "Disk hygiene" section.
134
-
135
- ## Cloud proxy
136
-
137
- The same proxy code also runs as the company-hosted fallback when the user
138
- pool can't serve a viewer. Keep the proxy host-agnostic so it runs unchanged on
139
- rented infra (flat-rate/unmetered bandwidth — Hetzner dedicated / OVH; NOT
140
- metered-egress clouds). Provider/economics analysis in the parent
141
- `../CLAUDE.md` "Cloud proxy" section.
142
-
143
- ## Changelog
144
-
145
- Every behavioural change must be recorded in `CHANGELOG.md` — add an entry under
146
- a new `## <version>` heading at the top, following the existing
147
- `- **New**/**Fix**/**Chore**:` format.
148
-
149
- **Do NOT edit `package.json` version.** `npm run patch`/`minor` runs `npm
150
- version …` which bumps it. Write the CHANGELOG entry at the version that bump
151
- will produce: **current `package.json` version + 1 patch** (or + 1 minor).
152
- Accumulate bullets into that single pending entry until it's published. See the
153
- parent `../CLAUDE.md`.
154
-
155
- ## Release
156
-
157
- `npm run patch` (publishes to npm + pushes tags). The HA addon then needs its
158
- own version bump to pull the new package. Publish proxy BEFORE bumping the addon.
159
-
160
- **Any proxy change requires bumping the ha-addon version** (`ha-addon/torrent_tv_proxy/config.yaml`). The addon installs the proxy from npm at build time and the build is cached; without a version bump the plugin will NOT update and keeps running the old proxy. So after `npm run patch`, always bump the addon `config.yaml` version, push, and update the addon.
1
+ # proxy — @torrent-tv/proxy (WebTorrent + ffmpeg)
2
+
3
+ Downloads a torrent and streams the chosen file to the browser, transcoding to
4
+ HLS only when needed. See the parent `../CLAUDE.md` for the overall architecture
5
+ and release process.
6
+
7
+ ## Deployment-agnostic — important
8
+
9
+ The HA addon is only ONE way to run this; bare npm and Docker are planned. Keep
10
+ all code free of Home-Assistant assumptions. Anything host-specific (GPU
11
+ devices, ffmpeg build, CLI flags) belongs in the `ha-addon` layer. Hardware
12
+ detection must probe at runtime and fall back gracefully; do not assume a
13
+ Linux-only host (e.g. POSIX-only signals must degrade elsewhere).
14
+
15
+ ## Layout
16
+
17
+ - `bin/cli.js` — CLI entry; resolves `ffmpegBin` (uses `--ffmpeg-bin` if given,
18
+ else bundled ffmpeg-static, else PATH `ffmpeg`).
19
+ - `server.js` — Fastify setup; detects the video encoder at startup
20
+ (`detectVideoEncoder`) and passes it to `HlsSessionManager`.
21
+ - `routes/<path>/<method>.js` — same convention as the server repo.
22
+ - `routes/stream/get.js` — byte-range torrent file streaming (HTTP 206).
23
+ - `routes/api/playback-plan/post.js` — codec/container/duration probe result.
24
+ - `routes/transcode/session-file/get.js` — serves HLS playlist/segments;
25
+ long-polls while a segment is being produced, returns retryable 503 (never
26
+ 202 — hls.js can't consume it).
27
+ - `services/`:
28
+ - `demand/` — what anybody wants, in BYTES: `Window` (claimant, file, byte
29
+ range, urgency), `Urgency` (BLOCKED / NEAR / AHEAD / TAIL / BEHIND),
30
+ `DemandRegister` (live windows by claimant), `pieces.js` (the one place
31
+ bytes become piece numbers). No WebTorrent, no piece store, no pieces.
32
+ - `download/` — `SwarmSelection`, the ONLY thing that calls `select`,
33
+ `deselect` or `critical`, and `registry.js`, which holds one per torrent and
34
+ owns the cross-torrent rule that withholds the speculative levels while
35
+ anything urgent is missing anywhere. See `docs/download-architecture.md`.
36
+ - `container/` — domain layer: `Container` (abstract, RFC 9559 / ISO 14496-12),
37
+ `MatroskaContainer` / `Mp4Container` / `AviContainer`, `ContainerFactory`
38
+ (sniff 16 bytes → precise subclass). See `docs/container-architecture.md`.
39
+ - `tracks/` — domain layer: `ContainerTrack` (base: TrackNumber, declaredIndex,
40
+ language/BCP47, isEnabled/isDefault) → `VideoTrack` / `AudioTrack` /
41
+ `SubtitleTrack` → `TextSubtitleTrack` / `ImageSubtitleTrack`,
42
+ `ExternalSubtitleFile`. Spec-accurate flags (FlagForced only on subtitles per
43
+ RFC 9559 §5.1.4.1, FlagOriginal/Commentary only on audio, tkhd
44
+ track_enabled / alternate_group, elng BCP47).
45
+ - `orchestrators/` — application layer: `ContainerOrchestrator` (detect + per-file
46
+ cache, `getTracks`/`getKeyframeIndex`), `SubtitleOrchestrator` (wraps
47
+ `torrent-worker/subtitle-cues.js` + `Container` tracks, warm/push). The walk
48
+ itself is `MatroskaContainer.walkHeldClusters` / `Mp4Container.readHeldSamples`;
49
+ `subtitle-cues.js` supplies the torrent's read policy and keeps the cursor.
50
+ - `controllers/` interface layer: `PlaybackController` / `SubtitleController`
51
+ (thin adapters over orchestrators; routes depend on controllers, not services).
52
+ `routes/*` are now thin HTTP translators.
53
+ - `container-index/`what is not specific to one media kind: EBML element
54
+ walking and the Matroska/MP4/AVI keyframe tables. Used internally by
55
+ `container/*`, deprecated as a direct import. Everything a container states
56
+ about its own SUBTITLES — track table, Cues, blocks in a cluster, sample
57
+ table, the walk of what is downloaded lives in the container class.
58
+ - `docs/download-architecture.md` the two axes of downloading: what is
59
+ wanted (`demand/`) against what the swarm is told (`download/`), why urgency
60
+ is not a number given to the library, and why the speculative levels are
61
+ withdrawn rather than lowered.
62
+ - `docs/logs.md` — where to find logs (HA `docker logs` + `/data/proxy.log`, DO
63
+ `infra-server-1` with forwarded frontend `POST /api/client-logs`). Browser
64
+ console not needed.
65
+ - `playback-planner.js` single ffmpeg probe returns audioCodec, videoCodec,
66
+ container, durationSeconds. `mode` is advisory; the browser decides.
67
+ - `hls-session-manager.js` one ffmpeg per (source, file, settings). Serves a
68
+ synthetic full-duration VOD playlist; produces segments on demand; restarts
69
+ ffmpeg at the requested segment for server-side seeking. Short idle TTL.
70
+ Uses the detected `videoEncoder` for video re-encode (copy otherwise).
71
+ - `hwaccel.js` — detect best H.264 encoder (NVENC/QSV/VAAPI/V4L2M2M) with a
72
+ STRICT startup test: encode `testsrc2` through the real HLS pipeline, then
73
+ verify each segment decodes independently (catches non-IDR/corrupted hw
74
+ output). Falls back to software libx264. Runtime fallback to software if a
75
+ hw encode later fails. v4l2m2m is gated by this test (fails on HA Yellow).
76
+ - `data-channel-handler.js`forwards WebRTC data-channel requests to the
77
+ local HTTP server (loopback), so the same routes serve both transports.
78
+
79
+ ## Gotchas
80
+
81
+ - Do NOT use `-hls_playlist_type event` — it breaks duration/seek. VOD only.
82
+ - A transitive dep (`ip-set`, via webtorrent) ships a hostile
83
+ `preinstall: npx only-allow pnpm` that breaks `npm install`. The addon works
84
+ around it with `--ignore-scripts` + a targeted rebuild of `node-datachannel`;
85
+ if you ever change install flow, keep that in mind.
86
+
87
+ ## Planned: public reachability (remote access)
88
+
89
+ Decided direction full plan in the parent `../CLAUDE.md`. Proxy-side pieces:
90
+
91
+ - **Auto port mapping** IMPLEMENTED (`services/port-mapper.js`, changelog
92
+ 2.9.16). UPnP IGD / NAT-PMP via `@silentbot1/nat-api` (now a direct dep; the
93
+ same lib WebTorrent uses for the torrent port). Maps TCP 9090 with a 2 h
94
+ auto-renewed lease, removed on shutdown (lease expiry covers hard kills).
95
+ Best-effort + start/stop timeouts; `--no-port-mapping` opts out;
96
+ `getMappedEndpoint()` exposes the external endpoint. NOT yet done: mapping the
97
+ **UDP** port WebRTC actually uses (it binds ephemeral UDP ports, so this TCP
98
+ mapping does not yet help WebRTC — roadmap step 3 in the parent CLAUDE.md).
99
+ Also pending (next iteration): a success log line in `port-mapper.js` `stop()`
100
+ (`removed mapping for TCP <port>`) — today stop() only logs on failure, so a
101
+ clean unmap on shutdown is silent.
102
+ - **Report endpoint to server** DONE (proxy 2.9.17). The mapped endpoint
103
+ is sent over the tunnel (`tunnel-client.sendEndpoint` `proxy-endpoint`) on
104
+ mapping success and on every tunnel (re)connect; the server dial-back-verifies
105
+ reachability (server 0.8.22, roadmap step 2).
106
+ - **HTTPS listener**: serve the existing routes over TLS with a per-proxy
107
+ certificate delivered by the server through the tunnel (persist cert+key
108
+ locally; ~90-day renewals are pushed the same way). Add CORS headers for the
109
+ web-app origin so hls.js / `<video>` can fetch cross-origin.
110
+ - Plain HTTPS becomes the preferred video transport; WebRTC data channel stays
111
+ as fallback for hosts where no port could be opened.
112
+ - **Later roadmap steps** (single staged roadmap in parent `../CLAUDE.md`,
113
+ WebRTC-first ordering): step 3 map the WebRTC UDP port (fixed
114
+ `portRangeBegin`/`End` + UPnP-map UDP); step 4 birthday-paradox port
115
+ prediction (open ~256 UDP sockets, inject predicted-port ICE candidates) for
116
+ symmetric NAT; step 5 IPv6-first (audit the candidate filter — do not drop
117
+ *global* v6) + STUN NAT pre-classification reported to the registry; then
118
+ the DNS+TLS path (steps 6–7); step 8 relay-then-upgrade (deferred).
119
+ - Future: ed25519 proxy identity (sign announcements), BEP 44 endpoint
120
+ announcements via the `bittorrent-dht` already bundled with WebTorrent.
121
+
122
+ All of this must stay deployment-agnostic (HA addon, bare npm, Docker).
123
+
124
+ ## Disk hygiene (open item torrent data is NOT cleaned up today)
125
+
126
+ HLS segments are handled (`hls-session-manager.js`: idle TTL, `disposeSession`,
127
+ `disposeAll`). Torrent data is **partially** handled: shutdown cleanup is done
128
+ (`TorrentPool.destroyAll()` with `destroyStore: true`, wired into the `onClose`
129
+ hook proxy 2.9.15), but `deselect()` only stops further download and nothing
130
+ removes a torrent's data **while the proxy keeps running**, nor sweeps orphans
131
+ left by a previous hard kill at startup.
132
+
133
+ Level 1 — remaining: `client.remove(torrent, { destroyStore: true })` on last-
134
+ file refcount 0 + idle TTL (mirror the HLS session model); startup sweep of
135
+ orphaned store dirs under `os.tmpdir()`; global disk cap with LRU eviction of
136
+ whole torrents. (Shutdown teardown ✅ done.)
137
+ Level 2 (research): sliding-window chunk store. Full rationale in the parent
138
+ `../CLAUDE.md` "Disk hygiene" section.
139
+
140
+ ## Cloud proxy
141
+
142
+ The same proxy code also runs as the company-hosted fallback when the user
143
+ pool can't serve a viewer. Keep the proxy host-agnostic so it runs unchanged on
144
+ rented infra (flat-rate/unmetered bandwidth — Hetzner dedicated / OVH; NOT
145
+ metered-egress clouds). Provider/economics analysis in the parent
146
+ `../CLAUDE.md` "Cloud proxy" section.
147
+
148
+ ## Changelog
149
+
150
+ Every behavioural change must be recorded in `CHANGELOG.md` add an entry under
151
+ a new `## <version>` heading at the top, following the existing
152
+ `- **New**/**Fix**/**Chore**:` format.
153
+
154
+ **Do NOT edit `package.json` version.** `npm run patch`/`minor` runs `npm
155
+ version …` which bumps it. Write the CHANGELOG entry at the version that bump
156
+ will produce: **current `package.json` version + 1 patch** (or + 1 minor).
157
+ Accumulate bullets into that single pending entry until it's published. See the
158
+ parent `../CLAUDE.md`.
159
+
160
+ ## Release
161
+
162
+ `npm run patch` (publishes to npm + pushes tags). The HA addon then needs its
163
+ own version bump to pull the new package. Publish proxy BEFORE bumping the addon.
164
+
165
+ **Any proxy change requires bumping the ha-addon version** (`ha-addon/torrent_tv_proxy/config.yaml`). The addon installs the proxy from npm at build time and the build is cached; without a version bump the plugin will NOT update and keeps running the old proxy. So after `npm run patch`, always bump the addon `config.yaml` version, push, and update the addon.