@torrent-tv/proxy 2.89.7 → 2.89.9
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/.claude/commands/opsx/apply.md +155 -155
- package/.claude/commands/opsx/archive.md +160 -160
- package/.claude/commands/opsx/explore.md +174 -174
- package/.claude/commands/opsx/propose.md +109 -109
- package/.claude/commands/opsx/sync.md +143 -143
- package/.claude/skills/openspec-apply-change/SKILL.md +159 -159
- package/.claude/skills/openspec-archive-change/SKILL.md +117 -117
- package/.claude/skills/openspec-explore/SKILL.md +289 -289
- package/.claude/skills/openspec-propose/SKILL.md +113 -113
- package/.claude/skills/openspec-sync-specs/SKILL.md +147 -147
- package/.dockerignore +5 -5
- package/AGENTS.md +363 -338
- package/CHANGELOG.md +2345 -2335
- package/Dockerfile +30 -30
- package/LICENSE +16 -16
- package/README.md +369 -369
- package/assets/calibration/NOTICE.md +100 -100
- package/assets/calibration/audio/NOTICE.md +19 -19
- package/assets/calibration/audio/manifest.json +98 -98
- package/assets/diagnostics/sctpstate.gdb +31 -31
- package/bin/cli.js +684 -684
- package/bin/thread-pool.js +30 -30
- package/biome.json +412 -412
- package/docs/browser-proxy-contract.md +155 -155
- package/docs/container-architecture.md +273 -273
- package/docs/download-architecture.md +261 -261
- package/docs/encode-architecture.md +765 -765
- package/docs/encode-run-state.md +96 -96
- package/docs/logs.md +97 -97
- package/docs/playback-start-forecast.md +113 -113
- package/docs/socks5-egress-research.md +114 -114
- package/docs/storage-architecture.md +273 -273
- package/knip.json +14 -14
- package/openspec/changes/adaptive-bitrate/design.md +92 -92
- package/openspec/changes/adaptive-bitrate/proposal.md +56 -56
- package/openspec/changes/adaptive-bitrate/specs/adaptive-bitrate/spec.md +51 -51
- package/openspec/changes/adaptive-bitrate/tasks.md +40 -40
- package/openspec/changes/binary-distribution/.openspec.yaml +2 -2
- package/openspec/changes/binary-distribution/proposal.md +53 -53
- package/openspec/changes/chunked-request-bodies/design.md +81 -81
- package/openspec/changes/chunked-request-bodies/proposal.md +53 -53
- package/openspec/changes/chunked-request-bodies/specs/chunked-request-bodies/spec.md +30 -30
- package/openspec/changes/chunked-request-bodies/tasks.md +40 -40
- package/openspec/changes/cold-start/design.md +98 -98
- package/openspec/changes/cold-start/proposal.md +62 -62
- package/openspec/changes/cold-start/specs/cold-start/spec.md +47 -47
- package/openspec/changes/cold-start/tasks.md +48 -48
- package/openspec/changes/disk-cap/.openspec.yaml +2 -2
- package/openspec/changes/disk-cap/proposal.md +37 -37
- package/openspec/changes/disk-cap/specs/disk-cap/spec.md +25 -25
- package/openspec/changes/disk-cap/tasks.md +19 -19
- package/openspec/changes/proxy-observability/.openspec.yaml +2 -2
- package/openspec/changes/proxy-observability/design.md +38 -38
- package/openspec/changes/proxy-observability/proposal.md +49 -49
- package/openspec/changes/proxy-observability/specs/observability/spec.md +33 -33
- package/openspec/changes/proxy-observability/tasks.md +21 -21
- package/openspec/changes/seek-debounce/design.md +118 -118
- package/openspec/changes/seek-debounce/proposal.md +59 -59
- package/openspec/changes/seek-debounce/specs/seek-debounce/spec.md +41 -41
- package/openspec/changes/seek-debounce/tasks.md +33 -33
- package/openspec/changes/subtitle-language/.openspec.yaml +2 -2
- package/openspec/changes/subtitle-language/proposal.md +50 -50
- package/openspec/changes/subtitle-language/specs/subtitle-language/spec.md +34 -34
- package/openspec/changes/subtitle-language/tasks.md +26 -26
- package/openspec/changes/track-selection/.openspec.yaml +2 -2
- package/openspec/changes/track-selection/design.md +47 -47
- package/openspec/changes/track-selection/proposal.md +45 -45
- package/openspec/changes/track-selection/specs/track-selection/spec.md +41 -41
- package/openspec/changes/track-selection/tasks.md +20 -20
- package/openspec/changes/transcode-quality/.openspec.yaml +2 -2
- package/openspec/changes/transcode-quality/proposal.md +51 -51
- package/openspec/changes/transcode-quality/specs/transcode-quality/spec.md +139 -139
- package/openspec/changes/transcode-quality/tasks.md +63 -63
- package/openspec/config.yaml +38 -38
- package/package.json +51 -50
- package/public/.well-known/appspecific/com.chrome.devtools.json +1 -1
- package/research/delivery-wedge-stand-ladder-2026-09-13.md +329 -329
- package/research/double-spawn-2026-09-10.md +171 -171
- package/research/handover-2026-09-13.md +209 -209
- package/research/handover-reader-claims-removal-2026-09-12.md +166 -166
- package/research/piece-withdrawn-but-still-claimed-2026-09-12.md +175 -175
- package/research/preset-benchmark-size-scaling-2026-08-22.md +55 -55
- package/research/priority-map-is-the-truth-2026-09-12.md +225 -225
- package/routes/api/client-logs/post.js +86 -86
- package/routes/api/delivery-sink/get.js +72 -72
- package/routes/api/link-probe/get.js +51 -51
- package/routes/api/playback-plan/audio-tracks/post.js +29 -29
- package/routes/api/playback-plan/post.js +53 -53
- package/routes/api/sources/files/get.js +106 -106
- package/routes/api/sources/post.js +36 -36
- package/routes/api/sources/stats/get.js +132 -132
- package/routes/api/sources/warm/post.js +217 -217
- package/routes/api/subtitles/get.js +230 -230
- package/routes/api/transcode-sessions/fragment-far/post.js +60 -60
- package/routes/api/transcode-sessions/net-report/post.js +138 -138
- package/routes/api/transcode-sessions/post.js +178 -178
- package/routes/api/transcode-sessions/progress/get.js +27 -27
- package/routes/api/transcode-sessions/release/post.js +41 -41
- package/routes/api/transcode-sessions/seek/post.js +63 -63
- package/routes/health/get.js +13 -13
- package/routes/healthz/get.js +13 -13
- package/routes/stream/get.js +416 -416
- package/routes/transcode/audio-file/get.js +64 -64
- package/routes/transcode/audio-warm/get.js +95 -95
- package/routes/transcode/session-file/get.js +52 -52
- package/routes/transcode/variant-file/get.js +95 -95
- package/routes/transcode/variant-warm/get.js +84 -84
- package/scripts/build-audio-samples.mjs +31 -31
- package/scripts/render-run-graph.js +173 -173
- package/server.js +748 -748
- package/services/encode/CoverageMap.js +428 -428
- package/services/encode/CushionReport.js +345 -345
- package/services/encode/EncodeAdmission.js +376 -376
- package/services/encode/EncodeOrchestrator.js +1192 -1192
- package/services/encode/EncodePlan.js +1368 -1368
- package/services/encode/EncodeRun.js +36 -12
- package/services/encode/Encoder.js +142 -142
- package/services/encode/EncoderSelection.js +38 -38
- package/services/encode/LocalObservations.js +359 -359
- package/services/encode/NvencEncoder.js +50 -50
- package/services/encode/OutputOpening.js +784 -784
- package/services/encode/OutputTimes.js +579 -579
- package/services/encode/QsvEncoder.js +58 -58
- package/services/encode/Renditions.js +2283 -2283
- package/services/encode/RunClock.js +87 -87
- package/services/encode/RunProgress.js +79 -79
- package/services/encode/SegmentDemand.js +95 -95
- package/services/encode/SoftwareEncoder.js +121 -121
- package/services/encode/V4l2m2mEncoder.js +53 -53
- package/services/encode/VaapiEncoder.js +66 -66
- package/services/encode/args.js +418 -418
- package/services/encode/audio-calibration.js +67 -67
- package/services/encode/audio-work-rate.js +15 -15
- package/services/encode/available-share.js +89 -89
- package/services/encode/calibration.js +361 -361
- package/services/encode/contention.js +128 -128
- package/services/encode/decode-cost-fit.js +363 -363
- package/services/encode/encode-exit.js +116 -116
- package/services/encode/encode-run-state.js +551 -551
- package/services/encode/encoder-readings.js +43 -43
- package/services/encode/fingerprint.js +322 -322
- package/services/encode/host-load.js +174 -174
- package/services/encode/hwaccel.js +1894 -1894
- package/services/encode/index.js +9 -9
- package/services/encode/learned-median.js +90 -90
- package/services/encode/output/EncodedOutput.js +57 -57
- package/services/encode/output/Output.js +131 -131
- package/services/encode/output/OutputCatalog.js +414 -414
- package/services/encode/output/OutputSpec.js +390 -390
- package/services/encode/output/Timeline.js +308 -308
- package/services/encode/output/cut-grid.js +107 -107
- package/services/encode/output/index.js +24 -24
- package/services/encode/output/ladder.js +32 -32
- package/services/encode/output/playlists.js +284 -284
- package/services/encode/output/rates.js +125 -125
- package/services/encode/output-key-format.js +21 -21
- package/services/encode/quality/EncodeCost.js +1043 -1043
- package/services/encode/quality/HostLoad.js +525 -525
- package/services/encode/quality/HostTimings.js +249 -249
- package/services/encode/quality/OutputQualityState.js +24 -24
- package/services/encode/quality/QualityController.js +758 -758
- package/services/encode/quality/QualityOffer.js +416 -416
- package/services/encode/quality/drain-threat.js +47 -47
- package/services/encode/quality/link-budget.js +337 -337
- package/services/encode/quality/output-format.js +319 -319
- package/services/encode/quality/serving-output.js +216 -216
- package/services/encode/quality/visible-rung.js +57 -57
- package/services/encode/run-budget.js +97 -97
- package/services/encode/run-command.js +757 -757
- package/services/encode/run-costs.js +155 -155
- package/services/encode/run-inputs.js +53 -53
- package/services/encode/segment-formats/fmp4.js +476 -476
- package/services/encode/segment-formats/init-compat.js +324 -324
- package/services/encode/segment-formats/mpegts.js +134 -134
- package/services/encode/start-stop-cost.js +178 -178
- package/services/encode/throughput.js +97 -97
- package/services/encode/torrent-cost.js +88 -88
- package/services/identity/installation-id.js +38 -38
- package/services/media/ContainerOrchestrator.js +202 -202
- package/services/media/KeyframeTables.js +356 -356
- package/services/media/SourceFile.js +298 -298
- package/services/media/SubtitleCues.js +592 -592
- package/services/media/SubtitleOrchestrator.js +167 -167
- package/services/media/audio-inventory.js +299 -299
- package/services/media/container/AviContainer.js +268 -268
- package/services/media/container/Container.js +632 -632
- package/services/media/container/ContainerFactory.js +38 -38
- package/services/media/container/KeyframeTable.js +272 -272
- package/services/media/container/MatroskaContainer.js +1031 -1031
- package/services/media/container/Mp4Container.js +1354 -1354
- package/services/media/container/SubtitleFileContainer.js +339 -339
- package/services/media/container/ebml-reader.js +159 -159
- package/services/media/container/ebml-stream.js +174 -174
- package/services/media/container/matroska-clusters.js +1165 -1165
- package/services/media/container/unavailable.js +77 -77
- package/services/media/ffmpeg-banner.js +260 -260
- package/services/media/keyframe-probe.js +157 -157
- package/services/media/media-info-probe.js +93 -93
- package/services/media/playback-planner.js +931 -931
- package/services/media/tracks/AudioTrack.js +143 -143
- package/services/media/tracks/ContainerTrack.js +84 -84
- package/services/media/tracks/ImageSubtitleTrack.js +19 -19
- package/services/media/tracks/SubtitleTrack.js +38 -38
- package/services/media/tracks/TextSubtitleTrack.js +295 -295
- package/services/media/tracks/VideoTrack.js +33 -33
- package/services/media/tracks/audio-bound.js +233 -233
- package/services/media/tracks/index.js +15 -15
- package/services/media/tracks/language-detect.js +174 -174
- package/services/server/OutputLifecycle.js +418 -418
- package/services/server/SegmentServing.js +1152 -1152
- package/services/server/ViewerRequests.js +785 -785
- package/services/server/WaitLedger.js +142 -142
- package/services/server/controllers/PlaybackController.js +40 -40
- package/services/server/controllers/SubtitleController.js +109 -109
- package/services/server/http-responses.js +60 -60
- package/services/server/transcode-session-files.js +325 -325
- package/services/server/wire-outputs.js +1029 -1029
- package/services/storage/Diagnostics.js +202 -202
- package/services/storage/MachineBudget.js +235 -235
- package/services/storage/allowance.js +107 -107
- package/services/storage/core-dumps.js +106 -106
- package/services/storage/files/CompletedFiles.js +391 -391
- package/services/storage/files/piece-from-whole-file.js +118 -118
- package/services/storage/free.js +71 -71
- package/services/storage/keep.js +48 -48
- package/services/storage/machine-memory.js +56 -56
- package/services/storage/memory-report.js +575 -575
- package/services/storage/piece-store/piece-disk-store.js +539 -539
- package/services/storage/piece-store/piece-lru.js +495 -495
- package/services/storage/piece-store/shared-piece-store.js +1937 -1937
- package/services/storage/returns.js +103 -103
- package/services/storage/segment-store/SegmentStore.js +1294 -1294
- package/services/storage/wire.js +175 -175
- package/services/torrent/Contents.js +382 -382
- package/services/torrent/demand/DemandRegister.js +202 -202
- package/services/torrent/demand/Urgency.js +137 -137
- package/services/torrent/demand/Window.js +118 -118
- package/services/torrent/demand/index.js +8 -8
- package/services/torrent/demand/pieces.js +140 -140
- package/services/torrent/download/SwarmSelection.js +386 -386
- package/services/torrent/download/registry.js +102 -102
- package/services/torrent/download/withdraw-claim.js +80 -80
- package/services/torrent/episode-naming.js +182 -182
- package/services/torrent/files.js +455 -455
- package/services/torrent/naming.js +619 -619
- package/services/torrent/piece-store-of.js +29 -29
- package/services/torrent/supply-margin.js +264 -264
- package/services/torrent/torrent-pool.js +2688 -2688
- package/services/torrent/worker/background-fill.js +213 -213
- package/services/torrent/worker/channel.js +271 -271
- package/services/torrent/worker/client.js +836 -836
- package/services/torrent/worker/fastest-wires.js +342 -342
- package/services/torrent/worker/handle-state.js +23 -23
- package/services/torrent/worker/held-bytes.js +231 -231
- package/services/torrent/worker/install-webrtc-shim.js +32 -32
- package/services/torrent/worker/piece-reader.js +1078 -1078
- package/services/torrent/worker/pool-adapter.js +371 -371
- package/services/torrent/worker/protocol.js +184 -184
- package/services/torrent/worker/resume-warm.js +107 -107
- package/services/torrent/worker/webrtc-shim.js +219 -219
- package/services/torrent/worker/worker.js +1137 -1137
- package/services/transport/data-channel-handler.js +1406 -1373
- package/services/transport/delivery-probe.js +798 -842
- package/services/transport/health-collector.js +53 -53
- package/services/transport/nat-classifier.js +231 -231
- package/services/transport/packet-witness.js +808 -808
- package/services/transport/port-mapper.js +235 -235
- package/services/transport/registry-api.js +81 -81
- package/services/transport/tunnel-client.js +447 -447
- package/services/transport/usrsctp-state.js +175 -175
- package/services/transport/webrtc-manager.js +484 -484
- package/services/viewer/Assignments.js +340 -340
- package/services/viewer/PriorityMap.js +421 -421
- package/services/viewer/PriorityOrchestrator.js +325 -325
- package/services/viewer/Viewer.js +691 -691
- package/services/viewer/Viewers.js +368 -368
- package/services/viewer/active-output.js +37 -37
- package/services/viewer/audio-start.js +46 -46
- package/services/viewer/buffer-trend.js +81 -81
- package/services/viewer/choices.js +647 -647
- package/services/viewer/media-time.js +355 -355
- package/services/viewer/playback-readiness.js +635 -635
- package/services/viewer/positions.js +126 -126
- package/services/viewer/report-intake.js +46 -46
- package/store/source-registry.js +71 -71
- package/test/asset-paths.test.js +28 -28
- package/test/audio-buffer-continuity.test.js +77 -77
- package/test/audio-calibration.test.js +23 -23
- package/test/audio-inventory.test.js +212 -212
- package/test/audio-track-bitrate.test.js +40 -40
- package/test/auto-quality-step.test.js +762 -762
- package/test/available-share.test.js +76 -76
- package/test/background-fill.test.js +190 -190
- package/test/client-log-file.test.js +110 -110
- package/test/coalesce.test.js +39 -39
- package/test/completed-files.test.js +115 -115
- package/test/concurrent-cost.test.js +148 -148
- package/test/container-media-info.test.js +228 -228
- package/test/contention.test.js +76 -76
- package/test/core-dumps.test.js +57 -57
- package/test/coverage-follows-the-disk.test.js +233 -228
- package/test/coverage-map.test.js +195 -195
- package/test/cue-push-carries-what-the-walk-found.test.js +58 -58
- package/test/cut-times-timeline.test.js +65 -65
- package/test/cuts-follow-published-grid.test.js +109 -109
- package/test/data-channel-frame.test.js +63 -63
- package/test/data-channel-viewer-lifecycle.test.js +162 -92
- package/test/dead-torrent-handle.test.js +52 -52
- package/test/declared-rates.test.js +116 -116
- package/test/declared-tracks.test.js +43 -43
- package/test/decode-cost-fit.test.js +202 -202
- package/test/decode-cost.test.js +475 -475
- package/test/delivery-probe-field.test.js +173 -0
- package/test/delivery-probe.test.js +382 -393
- package/test/demand-register.test.js +206 -206
- package/test/dht-bootstrap.test.js +72 -72
- package/test/drain-threat.test.js +65 -65
- package/test/duplicate-add.test.js +48 -48
- package/test/encode-admission.test.js +146 -146
- package/test/encode-cost.test.js +275 -275
- package/test/encode-exit.test.js +111 -111
- package/test/encode-orchestrator.test.js +426 -426
- package/test/encode-plan-viewers.test.js +725 -725
- package/test/encode-plan.test.js +545 -545
- package/test/encode-run-state.test.js +314 -314
- package/test/encode-run.test.js +20 -0
- package/test/encode-slope.test.js +46 -46
- package/test/encoded-output.test.js +39 -39
- package/test/encoder-kinds.test.js +122 -122
- package/test/encoder-readings.test.js +68 -68
- package/test/episode-naming.test.js +131 -131
- package/test/every-claimant-is-told-its-share.test.js +152 -152
- package/test/failed-encoder-still-serves-what-exists.test.js +354 -354
- package/test/failed-start-breaker.test.js +202 -202
- package/test/fastest-wires.test.js +143 -143
- package/test/ffmpeg-stream-counts.test.js +78 -78
- package/test/file-edges.test.js +191 -191
- package/test/fixtures/audio-frame-boundary.json +1 -1
- package/test/fmp4-self-contained.test.js +80 -80
- package/test/fmp4-timestamps.test.js +140 -140
- package/test/fmp4-track-completeness.test.js +41 -41
- package/test/format-keyed-outputs.test.js +78 -78
- package/test/health-metrics.test.js +36 -38
- package/test/held-read-ownership.test.js +77 -77
- package/test/held-request-width.test.js +157 -157
- package/test/helpers/encode-run.js +248 -240
- package/test/helpers/held-file.js +77 -77
- package/test/helpers/manager.js +62 -62
- package/test/helpers/matroska-file.js +296 -296
- package/test/helpers/output-spec.js +63 -63
- package/test/host-load.test.js +68 -68
- package/test/index-accuracy-is-about-the-file.test.js +128 -128
- package/test/init-compat.test.js +219 -219
- package/test/input-lost-quiets-the-plan.test.js +261 -261
- package/test/input-unavailable.test.js +48 -48
- package/test/installation-id.test.js +39 -39
- package/test/keeping-period.test.js +83 -83
- package/test/keyframe-index-accuracy.test.js +188 -188
- package/test/keyframe-table-budget.test.js +123 -123
- package/test/keyframes-belong-to-the-file.test.js +249 -249
- package/test/learned-median.test.js +37 -37
- package/test/letting-go-asks-who-is-watching.test.js +191 -191
- package/test/limit-row-by-area.test.js +60 -60
- package/test/link-budget.test.js +111 -111
- package/test/link-probe.test.js +56 -56
- package/test/local-encoding-data.test.js +273 -273
- package/test/logger-repeats.test.js +134 -134
- package/test/look-ahead-coverage.test.js +56 -56
- package/test/manager-surface.test.js +291 -291
- package/test/matroska-cluster-discovery.test.js +323 -323
- package/test/matroska-cues-track.test.js +192 -192
- package/test/media-time.test.js +62 -62
- package/test/memory-budget.test.js +390 -390
- package/test/move-cost.test.js +216 -216
- package/test/mp4-subtitles.test.js +173 -173
- package/test/one-authority.test.js +285 -285
- package/test/one-budget.test.js +149 -149
- package/test/one-output-one-session.test.js +273 -273
- package/test/one-resource-divided.test.js +185 -185
- package/test/one-serving-output-per-height.test.js +458 -458
- package/test/orchestrator-wired.test.js +207 -207
- package/test/output-catalog.test.js +39 -39
- package/test/output-shape.test.js +21 -21
- package/test/output-spec.test.js +251 -251
- package/test/output-speed.test.js +92 -87
- package/test/outputs-being-prepared.test.js +40 -40
- package/test/packet-witness-ring.test.js +236 -236
- package/test/packet-witness.test.js +148 -148
- package/test/piece-disk-store.test.js +401 -401
- package/test/piece-from-whole-file.test.js +129 -129
- package/test/piece-lru.test.js +319 -319
- package/test/piece-reader.test.js +162 -162
- package/test/piece-selection-offset.test.js +85 -85
- package/test/piece-store-eviction.test.js +595 -595
- package/test/piece-store-never-refuses.test.js +153 -153
- package/test/piece-store-reservations.test.js +403 -403
- package/test/piece-store-slow-disk.test.js +159 -159
- package/test/piece-tail.test.js +97 -97
- package/test/plan-host-timings.test.js +68 -68
- package/test/plan-is-steady.test.js +225 -225
- package/test/playback-readiness.test.js +518 -518
- package/test/playback-start-regressions.test.js +101 -101
- package/test/priority-map-download.test.js +174 -174
- package/test/priority-map-emptied.test.js +204 -204
- package/test/priority-map-per-output.test.js +215 -215
- package/test/priority-map.test.js +163 -163
- package/test/probe-wedge-certainty.test.js +60 -60
- package/test/produced-copy-choice.test.js +213 -213
- package/test/published-timeline.test.js +83 -83
- package/test/quality-offer.test.js +160 -160
- package/test/quality-variants.test.js +1274 -1270
- package/test/rate-control-in-the-output.test.js +181 -180
- package/test/read-survives-withdrawal.test.js +164 -164
- package/test/read-window.test.js +365 -365
- package/test/reads-not-yet-arrived.test.js +218 -218
- package/test/resume-warm.test.js +39 -39
- package/test/run-graph-drift.test.js +37 -37
- package/test/run-inputs.test.js +80 -80
- package/test/run-intervals.test.js +100 -100
- package/test/run-position-follows-published-grid.test.js +89 -89
- package/test/run-progress.test.js +64 -64
- package/test/same-height-switch.test.js +663 -663
- package/test/seek-frees-the-viewers-requests.test.js +217 -217
- package/test/seek-landing.test.js +109 -109
- package/test/seek-target-not-superseded.test.js +195 -195
- package/test/segment-closed-on-both-branches.test.js +114 -114
- package/test/segment-cut-times.test.js +63 -63
- package/test/segment-demand.test.js +80 -80
- package/test/segment-hold-supersede.test.js +91 -91
- package/test/segment-judged-by-its-own-header.test.js +222 -222
- package/test/segment-serve-wiring.test.js +481 -481
- package/test/segment-store-eviction.test.js +247 -247
- package/test/segment-store.test.js +352 -352
- package/test/segment-true-start.test.js +86 -86
- package/test/segments-are-shared.test.js +176 -176
- package/test/send-chunk-bytes.test.js +86 -86
- package/test/serving-existing-output.test.js +111 -111
- package/test/serving-output.test.js +102 -102
- package/test/shared-piece-store.test.js +310 -310
- package/test/sidecar-naming.test.js +142 -142
- package/test/soundtrack-rate-bound.test.js +289 -289
- package/test/source-file.test.js +133 -133
- package/test/source-files-route.test.js +113 -113
- package/test/source-registry.test.js +18 -18
- package/test/split-a-stretch.test.js +139 -139
- package/test/stale-request-after-seek.test.js +158 -158
- package/test/startup-readings.test.js +124 -124
- package/test/stream-route.test.js +237 -237
- package/test/subtitle-cue-framing.test.js +200 -200
- package/test/subtitle-cue-source.test.js +102 -102
- package/test/subtitle-cue-walk.test.js +385 -385
- package/test/subtitle-cursor.test.js +63 -63
- package/test/subtitle-defaults.test.js +118 -118
- package/test/subtitle-language.test.js +252 -252
- package/test/subtitle-metadata.test.js +15 -15
- package/test/subtitle-plan-waits.test.js +125 -125
- package/test/subtitle-track-numbering.test.js +391 -391
- package/test/supply-margin.test.js +190 -190
- package/test/swarm-follows-readers.test.js +174 -174
- package/test/swarm-reach.test.js +130 -130
- package/test/swarm-selection.test.js +220 -220
- package/test/tail-duplication.test.js +167 -167
- package/test/the-channel-has-both-ends.test.js +91 -91
- package/test/the-torrent-thread-serves-bytes.test.js +107 -107
- package/test/thread-pool.test.js +53 -53
- package/test/timeline.test.js +84 -84
- package/test/torrent-contents.test.js +235 -235
- package/test/torrent-cost.test.js +71 -71
- package/test/torrent-files.test.js +221 -221
- package/test/torrent-naming.test.js +255 -255
- package/test/tracks-begin-together.test.js +209 -209
- package/test/tunnel-renewal.test.js +167 -167
- package/test/two-viewers-one-picture.test.js +508 -508
- package/test/upload-hurry.test.js +186 -186
- package/test/usrsctp-state.test.js +131 -131
- package/test/video-facts.test.js +102 -102
- package/test/viewer-assignments.test.js +143 -143
- package/test/viewer-outputs.test.js +285 -285
- package/test/viewer-presence.test.js +116 -116
- package/test/viewer-requests-admission.test.js +92 -92
- package/test/viewer-starts-on-map.test.js +27 -27
- package/test/viewer-states.test.js +192 -189
- package/test/viewer-subtitle-subscription.test.js +96 -96
- package/test/viewer.test.js +139 -139
- package/test/viewing-generations.test.js +390 -390
- package/test/visible-rung.test.js +37 -37
- package/test/wait-ledger.test.js +100 -100
- package/test/webrtc-shim.test.js +149 -149
- package/test/wedge-certainty.test.js +131 -131
- package/test/whole-file-held-read.test.js +30 -30
- package/test/withdraw-piece-claim.test.js +212 -212
- package/test/worker-channel.test.js +158 -158
- package/utils/client-log-file.js +151 -151
- package/utils/coalesce.js +41 -41
- package/utils/logger.js +312 -312
- package/utils/parse-range.js +25 -25
- package/utils/perf.js +59 -59
- package/utils/torrent-source-key.js +38 -38
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
|
|
4
|
-
import { wedgeIsCertain } from "../services/transport/data-channel-handler.js";
|
|
5
|
-
import { PROBE_INTERVAL_MS } from "../services/transport/delivery-probe.js";
|
|
6
|
-
|
|
7
|
-
const MEGABYTE = 1024 * 1024;
|
|
8
|
-
|
|
9
|
-
test("a queue draining at the rate this link was measured at is not a wedge", () => {
|
|
10
|
-
// 8 MB at 16 MB/s is half a second of draining. Half a second in is normal.
|
|
11
|
-
const verdict = wedgeIsCertain({
|
|
12
|
-
queuedBytes: 8 * MEGABYTE,
|
|
13
|
-
bytesPerSecond: 16 * MEGABYTE,
|
|
14
|
-
flatForMs: 200
|
|
15
|
-
});
|
|
16
|
-
assert.equal(verdict.certain, false);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test("the counter standing still past the queue's own drain time is a wedge", () => {
|
|
20
|
-
const verdict = wedgeIsCertain({
|
|
21
|
-
queuedBytes: 8 * MEGABYTE,
|
|
22
|
-
bytesPerSecond: 16 * MEGABYTE,
|
|
23
|
-
flatForMs: 4000
|
|
24
|
-
});
|
|
25
|
-
assert.equal(verdict.certain, true);
|
|
26
|
-
assert.equal(verdict.needMs, 500);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("a big queue on a slow link is given the time it genuinely needs", () => {
|
|
30
|
-
// 67 MB at 1 MB/s is 67 seconds of honest draining — the field's own numbers
|
|
31
|
-
// for the wedged channel, at a rate a thin link could really be running at.
|
|
32
|
-
const patient = wedgeIsCertain({
|
|
33
|
-
queuedBytes: 67 * MEGABYTE,
|
|
34
|
-
bytesPerSecond: MEGABYTE,
|
|
35
|
-
flatForMs: 30_000
|
|
36
|
-
});
|
|
37
|
-
assert.equal(patient.certain, false);
|
|
38
|
-
const later = wedgeIsCertain({
|
|
39
|
-
queuedBytes: 67 * MEGABYTE,
|
|
40
|
-
bytesPerSecond: MEGABYTE,
|
|
41
|
-
flatForMs: 70_000
|
|
42
|
-
});
|
|
43
|
-
assert.equal(later.certain, true);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("the same queue on the link the field actually had is called quickly", () => {
|
|
47
|
-
// 67 MB at 18 MB/s is under four seconds. The field episode stood still for
|
|
48
|
-
// 3217 s; the previous rule waited a flat 30 s before recording anything.
|
|
49
|
-
const verdict = wedgeIsCertain({
|
|
50
|
-
queuedBytes: 67 * MEGABYTE,
|
|
51
|
-
bytesPerSecond: 18 * MEGABYTE,
|
|
52
|
-
flatForMs: 5000
|
|
53
|
-
});
|
|
54
|
-
assert.equal(verdict.certain, true);
|
|
55
|
-
assert.ok(verdict.needMs < 30_000);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("a tiny queue still waits for one round of probes", () => {
|
|
59
|
-
const verdict = wedgeIsCertain({
|
|
60
|
-
queuedBytes: 512,
|
|
61
|
-
bytesPerSecond: 16 * MEGABYTE,
|
|
62
|
-
flatForMs: PROBE_INTERVAL_MS - 1
|
|
63
|
-
});
|
|
64
|
-
assert.equal(verdict.certain, false);
|
|
65
|
-
assert.equal(verdict.needMs, PROBE_INTERVAL_MS);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("nothing queued is still a wedge when the counter has been flat long enough — the channel queue was 0 on the real wedge while usrsctp held 399 MB", () => {
|
|
69
|
-
const verdict = wedgeIsCertain({
|
|
70
|
-
queuedBytes: 0,
|
|
71
|
-
bytesPerSecond: 16 * MEGABYTE,
|
|
72
|
-
flatForMs: 600_000
|
|
73
|
-
});
|
|
74
|
-
assert.equal(verdict.certain, true);
|
|
75
|
-
assert.equal(verdict.needMs, PROBE_INTERVAL_MS);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("with no rate measured the answer is that nothing can be said", () => {
|
|
79
|
-
const verdict = wedgeIsCertain({
|
|
80
|
-
queuedBytes: 8 * MEGABYTE,
|
|
81
|
-
bytesPerSecond: 0,
|
|
82
|
-
flatForMs: 600_000
|
|
83
|
-
});
|
|
84
|
-
assert.equal(verdict.certain, false);
|
|
85
|
-
assert.equal(verdict.needMs, null);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("a pause no longer than this link's own longest healthy pause is not a wedge", () => {
|
|
89
|
-
// A retransmission timeout stops the accepted-byte counter dead: a full send
|
|
90
|
-
// buffer accepts nothing. If this connection has already paused 3 s while
|
|
91
|
-
// healthy, a 3 s pause says nothing.
|
|
92
|
-
const verdict = wedgeIsCertain({
|
|
93
|
-
queuedBytes: 8 * MEGABYTE,
|
|
94
|
-
bytesPerSecond: 18 * MEGABYTE,
|
|
95
|
-
flatForMs: 2500,
|
|
96
|
-
longestHealthyFlatMs: 3000
|
|
97
|
-
});
|
|
98
|
-
assert.equal(verdict.certain, false);
|
|
99
|
-
assert.equal(verdict.needMs, 3000);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("a pause longer than any this link has shown is a wedge", () => {
|
|
103
|
-
const verdict = wedgeIsCertain({
|
|
104
|
-
queuedBytes: 8 * MEGABYTE,
|
|
105
|
-
bytesPerSecond: 18 * MEGABYTE,
|
|
106
|
-
flatForMs: 3500,
|
|
107
|
-
longestHealthyFlatMs: 3000
|
|
108
|
-
});
|
|
109
|
-
assert.equal(verdict.certain, true);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test("the quiet-probe rate cannot be what the queue is divided by", () => {
|
|
113
|
-
// With the browser's buffer full, the only traffic is the probe: three
|
|
114
|
-
// channels, a few dozen bytes, twice a second. Dividing 8 MB by that gives
|
|
115
|
-
// six hours, and the wedge would never be called. The BEST rate seen is what
|
|
116
|
-
// the watcher keeps, so this case must not arise — pinned here as the
|
|
117
|
-
// arithmetic that made it matter.
|
|
118
|
-
const wrong = wedgeIsCertain({
|
|
119
|
-
queuedBytes: 8 * MEGABYTE,
|
|
120
|
-
bytesPerSecond: 360,
|
|
121
|
-
flatForMs: 60_000
|
|
122
|
-
});
|
|
123
|
-
assert.equal(wrong.certain, false);
|
|
124
|
-
assert.ok(wrong.needMs > 6 * 60 * 60 * 1000 - 1);
|
|
125
|
-
const right = wedgeIsCertain({
|
|
126
|
-
queuedBytes: 8 * MEGABYTE,
|
|
127
|
-
bytesPerSecond: 18 * MEGABYTE,
|
|
128
|
-
flatForMs: 60_000
|
|
129
|
-
});
|
|
130
|
-
assert.equal(right.certain, true);
|
|
131
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import { wedgeIsCertain } from "../services/transport/data-channel-handler.js";
|
|
5
|
+
import { PROBE_INTERVAL_MS } from "../services/transport/delivery-probe.js";
|
|
6
|
+
|
|
7
|
+
const MEGABYTE = 1024 * 1024;
|
|
8
|
+
|
|
9
|
+
test("a queue draining at the rate this link was measured at is not a wedge", () => {
|
|
10
|
+
// 8 MB at 16 MB/s is half a second of draining. Half a second in is normal.
|
|
11
|
+
const verdict = wedgeIsCertain({
|
|
12
|
+
queuedBytes: 8 * MEGABYTE,
|
|
13
|
+
bytesPerSecond: 16 * MEGABYTE,
|
|
14
|
+
flatForMs: 200
|
|
15
|
+
});
|
|
16
|
+
assert.equal(verdict.certain, false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("the counter standing still past the queue's own drain time is a wedge", () => {
|
|
20
|
+
const verdict = wedgeIsCertain({
|
|
21
|
+
queuedBytes: 8 * MEGABYTE,
|
|
22
|
+
bytesPerSecond: 16 * MEGABYTE,
|
|
23
|
+
flatForMs: 4000
|
|
24
|
+
});
|
|
25
|
+
assert.equal(verdict.certain, true);
|
|
26
|
+
assert.equal(verdict.needMs, 500);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("a big queue on a slow link is given the time it genuinely needs", () => {
|
|
30
|
+
// 67 MB at 1 MB/s is 67 seconds of honest draining — the field's own numbers
|
|
31
|
+
// for the wedged channel, at a rate a thin link could really be running at.
|
|
32
|
+
const patient = wedgeIsCertain({
|
|
33
|
+
queuedBytes: 67 * MEGABYTE,
|
|
34
|
+
bytesPerSecond: MEGABYTE,
|
|
35
|
+
flatForMs: 30_000
|
|
36
|
+
});
|
|
37
|
+
assert.equal(patient.certain, false);
|
|
38
|
+
const later = wedgeIsCertain({
|
|
39
|
+
queuedBytes: 67 * MEGABYTE,
|
|
40
|
+
bytesPerSecond: MEGABYTE,
|
|
41
|
+
flatForMs: 70_000
|
|
42
|
+
});
|
|
43
|
+
assert.equal(later.certain, true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("the same queue on the link the field actually had is called quickly", () => {
|
|
47
|
+
// 67 MB at 18 MB/s is under four seconds. The field episode stood still for
|
|
48
|
+
// 3217 s; the previous rule waited a flat 30 s before recording anything.
|
|
49
|
+
const verdict = wedgeIsCertain({
|
|
50
|
+
queuedBytes: 67 * MEGABYTE,
|
|
51
|
+
bytesPerSecond: 18 * MEGABYTE,
|
|
52
|
+
flatForMs: 5000
|
|
53
|
+
});
|
|
54
|
+
assert.equal(verdict.certain, true);
|
|
55
|
+
assert.ok(verdict.needMs < 30_000);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("a tiny queue still waits for one round of probes", () => {
|
|
59
|
+
const verdict = wedgeIsCertain({
|
|
60
|
+
queuedBytes: 512,
|
|
61
|
+
bytesPerSecond: 16 * MEGABYTE,
|
|
62
|
+
flatForMs: PROBE_INTERVAL_MS - 1
|
|
63
|
+
});
|
|
64
|
+
assert.equal(verdict.certain, false);
|
|
65
|
+
assert.equal(verdict.needMs, PROBE_INTERVAL_MS);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("nothing queued is still a wedge when the counter has been flat long enough — the channel queue was 0 on the real wedge while usrsctp held 399 MB", () => {
|
|
69
|
+
const verdict = wedgeIsCertain({
|
|
70
|
+
queuedBytes: 0,
|
|
71
|
+
bytesPerSecond: 16 * MEGABYTE,
|
|
72
|
+
flatForMs: 600_000
|
|
73
|
+
});
|
|
74
|
+
assert.equal(verdict.certain, true);
|
|
75
|
+
assert.equal(verdict.needMs, PROBE_INTERVAL_MS);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("with no rate measured the answer is that nothing can be said", () => {
|
|
79
|
+
const verdict = wedgeIsCertain({
|
|
80
|
+
queuedBytes: 8 * MEGABYTE,
|
|
81
|
+
bytesPerSecond: 0,
|
|
82
|
+
flatForMs: 600_000
|
|
83
|
+
});
|
|
84
|
+
assert.equal(verdict.certain, false);
|
|
85
|
+
assert.equal(verdict.needMs, null);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("a pause no longer than this link's own longest healthy pause is not a wedge", () => {
|
|
89
|
+
// A retransmission timeout stops the accepted-byte counter dead: a full send
|
|
90
|
+
// buffer accepts nothing. If this connection has already paused 3 s while
|
|
91
|
+
// healthy, a 3 s pause says nothing.
|
|
92
|
+
const verdict = wedgeIsCertain({
|
|
93
|
+
queuedBytes: 8 * MEGABYTE,
|
|
94
|
+
bytesPerSecond: 18 * MEGABYTE,
|
|
95
|
+
flatForMs: 2500,
|
|
96
|
+
longestHealthyFlatMs: 3000
|
|
97
|
+
});
|
|
98
|
+
assert.equal(verdict.certain, false);
|
|
99
|
+
assert.equal(verdict.needMs, 3000);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("a pause longer than any this link has shown is a wedge", () => {
|
|
103
|
+
const verdict = wedgeIsCertain({
|
|
104
|
+
queuedBytes: 8 * MEGABYTE,
|
|
105
|
+
bytesPerSecond: 18 * MEGABYTE,
|
|
106
|
+
flatForMs: 3500,
|
|
107
|
+
longestHealthyFlatMs: 3000
|
|
108
|
+
});
|
|
109
|
+
assert.equal(verdict.certain, true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("the quiet-probe rate cannot be what the queue is divided by", () => {
|
|
113
|
+
// With the browser's buffer full, the only traffic is the probe: three
|
|
114
|
+
// channels, a few dozen bytes, twice a second. Dividing 8 MB by that gives
|
|
115
|
+
// six hours, and the wedge would never be called. The BEST rate seen is what
|
|
116
|
+
// the watcher keeps, so this case must not arise — pinned here as the
|
|
117
|
+
// arithmetic that made it matter.
|
|
118
|
+
const wrong = wedgeIsCertain({
|
|
119
|
+
queuedBytes: 8 * MEGABYTE,
|
|
120
|
+
bytesPerSecond: 360,
|
|
121
|
+
flatForMs: 60_000
|
|
122
|
+
});
|
|
123
|
+
assert.equal(wrong.certain, false);
|
|
124
|
+
assert.ok(wrong.needMs > 6 * 60 * 60 * 1000 - 1);
|
|
125
|
+
const right = wedgeIsCertain({
|
|
126
|
+
queuedBytes: 8 * MEGABYTE,
|
|
127
|
+
bytesPerSecond: 18 * MEGABYTE,
|
|
128
|
+
flatForMs: 60_000
|
|
129
|
+
});
|
|
130
|
+
assert.equal(right.certain, true);
|
|
131
|
+
});
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file A file kept whole is read from the disk by the subtitle walk.
|
|
3
|
-
*
|
|
4
|
-
* Once a file is kept whole its pieces leave the torrent's store while the
|
|
5
|
-
* bitfield still says they are held, and a read through the torrent waited on
|
|
6
|
-
* a store that no longer had them (field 2026-10-01). The reading itself is
|
|
7
|
-
* checked here over a temporary file; the client that uses it starts the
|
|
8
|
-
* torrent thread and is not built.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import test from "node:test";
|
|
12
|
-
import assert from "node:assert/strict";
|
|
13
|
-
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
14
|
-
import os from "node:os";
|
|
15
|
-
import path from "node:path";
|
|
16
|
-
|
|
17
|
-
import { readWholeFile } from "../services/torrent/worker/client.js";
|
|
18
|
-
|
|
19
|
-
test("a range of a whole file is read from the disk, and a range past it is not here", async (t) => {
|
|
20
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), "ttv-whole-"));
|
|
21
|
-
t.after(() => rm(dir, { recursive: true, force: true }));
|
|
22
|
-
const file = path.join(dir, "film.mkv");
|
|
23
|
-
await writeFile(file, Buffer.from("0123456789"));
|
|
24
|
-
const whole = { path: file, length: 10, name: "film.mkv" };
|
|
25
|
-
|
|
26
|
-
assert.equal((await readWholeFile(whole, 2, 5)).toString(), "2345");
|
|
27
|
-
assert.equal((await readWholeFile(whole, 8, 20)).toString(), "89", "clamped to the file");
|
|
28
|
-
assert.equal(await readWholeFile(whole, 12, 20), null);
|
|
29
|
-
await assert.rejects(readWholeFile({ ...whole, path: path.join(dir, "gone.mkv") }, 0, 1), { code: "ENOENT" });
|
|
30
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file A file kept whole is read from the disk by the subtitle walk.
|
|
3
|
+
*
|
|
4
|
+
* Once a file is kept whole its pieces leave the torrent's store while the
|
|
5
|
+
* bitfield still says they are held, and a read through the torrent waited on
|
|
6
|
+
* a store that no longer had them (field 2026-10-01). The reading itself is
|
|
7
|
+
* checked here over a temporary file; the client that uses it starts the
|
|
8
|
+
* torrent thread and is not built.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
|
|
17
|
+
import { readWholeFile } from "../services/torrent/worker/client.js";
|
|
18
|
+
|
|
19
|
+
test("a range of a whole file is read from the disk, and a range past it is not here", async (t) => {
|
|
20
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "ttv-whole-"));
|
|
21
|
+
t.after(() => rm(dir, { recursive: true, force: true }));
|
|
22
|
+
const file = path.join(dir, "film.mkv");
|
|
23
|
+
await writeFile(file, Buffer.from("0123456789"));
|
|
24
|
+
const whole = { path: file, length: 10, name: "film.mkv" };
|
|
25
|
+
|
|
26
|
+
assert.equal((await readWholeFile(whole, 2, 5)).toString(), "2345");
|
|
27
|
+
assert.equal((await readWholeFile(whole, 8, 20)).toString(), "89", "clamped to the file");
|
|
28
|
+
assert.equal(await readWholeFile(whole, 12, 20), null);
|
|
29
|
+
await assert.rejects(readWholeFile({ ...whole, path: path.join(dir, "gone.mkv") }, 0, 1), { code: "ENOENT" });
|
|
30
|
+
});
|