@torrent-tv/proxy 2.87.21 → 2.88.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/.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 +322 -322
- package/CHANGELOG.md +2242 -2234
- package/Dockerfile +30 -30
- package/LICENSE +16 -16
- package/README.md +369 -369
- package/assets/calibration/NOTICE.md +100 -100
- package/assets/diagnostics/sctpstate.gdb +31 -31
- package/bin/cli.js +684 -684
- package/bin/thread-pool.js +30 -30
- package/biome.json +411 -411
- package/docs/browser-proxy-contract.md +1 -1
- package/docs/container-architecture.md +218 -218
- package/docs/download-architecture.md +261 -261
- package/docs/encode-architecture.md +729 -729
- package/docs/encode-run-state.md +96 -96
- package/docs/logs.md +97 -97
- package/docs/socks5-egress-research.md +114 -114
- package/docs/storage-architecture.md +267 -267
- 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 +50 -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 -100
- 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 +173 -173
- 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 +380 -380
- package/routes/transcode/audio-file/get.js +64 -64
- package/routes/transcode/audio-warm/get.js +84 -84
- 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/render-run-graph.js +173 -173
- package/server.js +725 -725
- 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 +1217 -1217
- package/services/encode/EncodePlan.js +1366 -1366
- package/services/encode/EncodeRun.js +813 -813
- package/services/encode/EncodeRuns.js +1235 -1235
- 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 +758 -758
- package/services/encode/OutputTimes.js +579 -579
- package/services/encode/QsvEncoder.js +58 -58
- package/services/encode/Renditions.js +2184 -2184
- package/services/encode/RunProgress.js +84 -84
- 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 +416 -416
- 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 +114 -114
- package/services/encode/encode-run-state.js +551 -551
- package/services/encode/encoder-readings.js +45 -45
- 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 +20 -20
- 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 +1141 -1141
- package/services/encode/quality/HostLoad.js +525 -525
- package/services/encode/quality/HostTimings.js +249 -249
- package/services/encode/quality/OutputQualityState.js +28 -28
- package/services/encode/quality/QualityController.js +935 -935
- package/services/encode/quality/QualityOffer.js +416 -416
- package/services/encode/quality/drain-threat.js +47 -47
- package/services/encode/quality/link-budget.js +254 -254
- package/services/encode/quality/output-format.js +315 -315
- 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 +754 -754
- package/services/encode/run-costs.js +155 -155
- package/services/encode/run-inputs.js +42 -42
- package/services/encode/segment-formats/fmp4.js +456 -456
- package/services/encode/segment-formats/index.js +85 -85
- package/services/encode/segment-formats/init-compat.js +324 -324
- package/services/encode/segment-formats/mp4-boxes.js +515 -515
- 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 +149 -149
- package/services/media/KeyframeTables.js +316 -316
- package/services/media/SourceFile.js +298 -298
- package/services/media/SubtitleCues.js +520 -520
- package/services/media/SubtitleOrchestrator.js +167 -167
- package/services/media/audio-inventory.js +245 -245
- package/services/media/container/AviContainer.js +266 -266
- package/services/media/container/Container.js +603 -603
- package/services/media/container/ContainerFactory.js +56 -56
- package/services/media/container/KeyframeTable.js +272 -272
- package/services/media/container/MatroskaContainer.js +1494 -1494
- package/services/media/container/Mp4Container.js +1244 -1244
- package/services/media/container/SubtitleFileContainer.js +339 -322
- package/services/media/container/ebml-reader.js +159 -159
- 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 +131 -131
- package/services/media/tracks/ContainerTrack.js +75 -75
- package/services/media/tracks/ImageSubtitleTrack.js +19 -19
- package/services/media/tracks/SubtitleTrack.js +38 -38
- package/services/media/tracks/TextSubtitleTrack.js +287 -287
- package/services/media/tracks/VideoTrack.js +33 -33
- 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 +1150 -1150
- package/services/server/ViewerRequests.js +760 -760
- 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/playback-readiness.js +696 -696
- package/services/server/transcode-session-files.js +325 -325
- package/services/server/wire-outputs.js +992 -992
- 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 +1931 -1931
- package/services/storage/returns.js +103 -103
- package/services/storage/segment-store/SegmentStore.js +1240 -1240
- package/services/storage/wire.js +175 -175
- package/services/torrent/Contents.js +382 -324
- 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 -0
- 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 +262 -262
- package/services/torrent/torrent-pool.js +2675 -2675
- package/services/torrent/worker/background-fill.js +213 -213
- package/services/torrent/worker/channel.js +271 -271
- package/services/torrent/worker/client.js +765 -765
- 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 +155 -155
- 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 +1129 -1129
- package/services/transport/data-channel-handler.js +1369 -1369
- package/services/transport/delivery-probe.js +842 -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 +390 -390
- 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/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-inventory.test.js +212 -212
- package/test/audio-track-bitrate.test.js +40 -40
- package/test/auto-quality-step.test.js +707 -707
- 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/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 +228 -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 +92 -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 +462 -462
- package/test/delivery-probe.test.js +393 -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 +283 -283
- package/test/encode-exit.test.js +111 -111
- package/test/encode-orchestrator.test.js +419 -419
- package/test/encode-plan-viewers.test.js +718 -718
- package/test/encode-plan.test.js +545 -545
- package/test/encode-run-state.test.js +314 -314
- package/test/encode-run.test.js +162 -162
- 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 +46 -46
- package/test/episode-naming.test.js +131 -0
- 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/fmp4-presentation-clock.test.js +147 -147
- 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 +38 -38
- package/test/held-request-width.test.js +157 -157
- package/test/helpers/encode-run.js +136 -136
- package/test/helpers/held-file.js +29 -29
- package/test/helpers/manager.js +57 -57
- 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 +102 -102
- 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 +292 -292
- package/test/matroska-cues-track.test.js +192 -192
- 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 +204 -204
- 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 +206 -206
- 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 +88 -88
- 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 +453 -453
- package/test/playback-start-regressions.test.js +99 -99
- 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 +162 -162
- package/test/quality-variants.test.js +1229 -1229
- package/test/rate-control-in-the-output.test.js +180 -180
- package/test/read-survives-withdrawal.test.js +164 -164
- package/test/read-window.test.js +365 -365
- 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 +65 -65
- package/test/same-height-switch.test.js +664 -664
- 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 +96 -96
- 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 +221 -221
- package/test/segment-serve-wiring.test.js +475 -475
- package/test/segment-store-eviction.test.js +247 -247
- package/test/segment-store.test.js +323 -323
- 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 +102 -102
- 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/source-file.test.js +133 -133
- package/test/source-files-route.test.js +12 -2
- 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 +209 -209
- 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 +370 -370
- 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 -0
- package/test/subtitle-track-numbering.test.js +386 -386
- package/test/supply-margin.test.js +177 -177
- 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 +407 -407
- 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 +89 -89
- package/test/viewer-states.test.js +189 -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/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/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,128 +1,128 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file What a second job costs on this machine — measured, because it is not
|
|
3
|
-
* the sum of two prices.
|
|
4
|
-
*
|
|
5
|
-
* Measured on the addon host 2026-08-18, decoding the same clip:
|
|
6
|
-
*
|
|
7
|
-
* | what else was running | decode speed | cost |
|
|
8
|
-
* |---|---|---|
|
|
9
|
-
* | nothing (cold) | 2.10-2.25x | 0.46 s/s |
|
|
10
|
-
* | nothing (hot, 68 °C) | 2.30-2.33x | 0.43 s/s |
|
|
11
|
-
* | one encoder | 0.79-0.90x | 1.18 s/s |
|
|
12
|
-
* | two encoders | 0.56-0.64x | 1.67 s/s |
|
|
13
|
-
*
|
|
14
|
-
* The same work costs **2.6× more** with one encoder beside it and 3.7× with
|
|
15
|
-
* two. Heat is not the cause — the hot idle machine was the fastest of all.
|
|
16
|
-
* Four cores share one narrow path to memory, and decoding and encoding both
|
|
17
|
-
* saturate it.
|
|
18
|
-
*
|
|
19
|
-
* That contradicts the shape of the budget, not just its constants. Everything
|
|
20
|
-
* in the quality offer adds seconds of work per second of content — this
|
|
21
|
-
* encode, plus that decode, plus what is already committed — and these readings
|
|
22
|
-
* say two jobs that each fit alone do not fit together. The availability
|
|
23
|
-
* correction in `encode/available-share.js` does not cover it either: that subtracts
|
|
24
|
-
* the share of the machine taken by work nobody has been charged for, while
|
|
25
|
-
* this is our own work colliding with itself.
|
|
26
|
-
*
|
|
27
|
-
* So the penalty is measured rather than derived, at startup, on the host it
|
|
28
|
-
* describes — and beyond the range that was measured it does not extrapolate:
|
|
29
|
-
* it holds the largest reading and says so, because nothing here knows what a
|
|
30
|
-
* fourth job would do.
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Penalties measured on this host, keyed by how many OTHER jobs were running.
|
|
35
|
-
*
|
|
36
|
-
* @typedef {Map<number, number>} ContentionPenalties
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The multiplier for a job's cost when `othersRunning` other jobs share the
|
|
41
|
-
* machine.
|
|
42
|
-
*
|
|
43
|
-
* @param {number} othersRunning
|
|
44
|
-
* @param {ContentionPenalties | null} measured
|
|
45
|
-
* @returns {{ penalty: number, measured: boolean, from: number }}
|
|
46
|
-
* `from` is the reading it came from — equal to `othersRunning` when one was
|
|
47
|
-
* measured for exactly that many, and the largest available otherwise.
|
|
48
|
-
*/
|
|
49
|
-
export function contentionPenalty(othersRunning, measured) {
|
|
50
|
-
const others = Number.isFinite(othersRunning) ? Math.max(0, Math.round(othersRunning)) : 0;
|
|
51
|
-
if (others === 0) {
|
|
52
|
-
// Alone on the machine is what every benchmark measures, so there is
|
|
53
|
-
// nothing to correct.
|
|
54
|
-
return { penalty: 1, measured: true, from: 0 };
|
|
55
|
-
}
|
|
56
|
-
if (!(measured instanceof Map) || measured.size === 0) {
|
|
57
|
-
// Nothing measured: the honest multiplier is 1, and the caller's own log
|
|
58
|
-
// says the prediction is uncorrected. Inventing a penalty would be the
|
|
59
|
-
// same mistake as inventing a fill rate.
|
|
60
|
-
return { penalty: 1, measured: false, from: 0 };
|
|
61
|
-
}
|
|
62
|
-
const exact = measured.get(others);
|
|
63
|
-
if (Number.isFinite(exact) && exact > 0) {
|
|
64
|
-
return { penalty: exact, measured: true, from: others };
|
|
65
|
-
}
|
|
66
|
-
// Beyond what was measured, hold the largest reading rather than continue the
|
|
67
|
-
// curve. Two readings say nothing about the shape past them, and a budget
|
|
68
|
-
// that extrapolates a memory bottleneck will be wrong in whichever direction
|
|
69
|
-
// it guesses.
|
|
70
|
-
let largestKey = 0;
|
|
71
|
-
let largestValue = 1;
|
|
72
|
-
for (const [key, value] of measured) {
|
|
73
|
-
if (key <= others && key > largestKey && Number.isFinite(value) && value > 0) {
|
|
74
|
-
largestKey = key;
|
|
75
|
-
largestValue = value;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (largestKey === 0) {
|
|
79
|
-
return { penalty: 1, measured: false, from: 0 };
|
|
80
|
-
}
|
|
81
|
-
return { penalty: largestValue, measured: true, from: largestKey };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* A cost, corrected for what else will be running.
|
|
86
|
-
*
|
|
87
|
-
* @param {number} costSecondsPerSecond - As the benchmarks priced it, alone.
|
|
88
|
-
* @param {number} othersRunning
|
|
89
|
-
* @param {ContentionPenalties | null} measured
|
|
90
|
-
* @returns {number}
|
|
91
|
-
*/
|
|
92
|
-
export function costWithContention(costSecondsPerSecond, othersRunning, measured) {
|
|
93
|
-
if (!Number.isFinite(costSecondsPerSecond) || costSecondsPerSecond <= 0) {
|
|
94
|
-
return costSecondsPerSecond;
|
|
95
|
-
}
|
|
96
|
-
return costSecondsPerSecond * contentionPenalty(othersRunning, measured).penalty;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Turn measured decode speeds into penalties.
|
|
101
|
-
*
|
|
102
|
-
* @param {number} aloneSpeed - Decode speed with the machine to itself.
|
|
103
|
-
* @param {Array<{ others: number, speed: number }>} beside - One reading per
|
|
104
|
-
* number of other jobs running.
|
|
105
|
-
* @returns {ContentionPenalties | null} Null when the alone reading is missing,
|
|
106
|
-
* since every penalty is relative to it.
|
|
107
|
-
*/
|
|
108
|
-
export function penaltiesFrom(aloneSpeed, beside) {
|
|
109
|
-
if (!Number.isFinite(aloneSpeed) || aloneSpeed <= 0) {
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
const penalties = new Map();
|
|
113
|
-
for (const reading of Array.isArray(beside) ? beside : []) {
|
|
114
|
-
const others = Number.isFinite(reading?.others) ? Math.round(reading.others) : null;
|
|
115
|
-
const speed = Number(reading?.speed);
|
|
116
|
-
if (others === null || others <= 0 || !Number.isFinite(speed) || speed <= 0) {
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
// Cost is the reciprocal of speed, so the penalty is the reciprocal ratio.
|
|
120
|
-
// A job that runs at half the speed costs twice as much.
|
|
121
|
-
const penalty = aloneSpeed / speed;
|
|
122
|
-
// Below 1 would mean the machine got FASTER for being busier. It happens in
|
|
123
|
-
// the noise on a fast host, and it is not a discovery — it is a reading
|
|
124
|
-
// that says there is no penalty to measure here.
|
|
125
|
-
penalties.set(others, penalty > 1 ? penalty : 1);
|
|
126
|
-
}
|
|
127
|
-
return penalties.size > 0 ? penalties : null;
|
|
128
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @file What a second job costs on this machine — measured, because it is not
|
|
3
|
+
* the sum of two prices.
|
|
4
|
+
*
|
|
5
|
+
* Measured on the addon host 2026-08-18, decoding the same clip:
|
|
6
|
+
*
|
|
7
|
+
* | what else was running | decode speed | cost |
|
|
8
|
+
* |---|---|---|
|
|
9
|
+
* | nothing (cold) | 2.10-2.25x | 0.46 s/s |
|
|
10
|
+
* | nothing (hot, 68 °C) | 2.30-2.33x | 0.43 s/s |
|
|
11
|
+
* | one encoder | 0.79-0.90x | 1.18 s/s |
|
|
12
|
+
* | two encoders | 0.56-0.64x | 1.67 s/s |
|
|
13
|
+
*
|
|
14
|
+
* The same work costs **2.6× more** with one encoder beside it and 3.7× with
|
|
15
|
+
* two. Heat is not the cause — the hot idle machine was the fastest of all.
|
|
16
|
+
* Four cores share one narrow path to memory, and decoding and encoding both
|
|
17
|
+
* saturate it.
|
|
18
|
+
*
|
|
19
|
+
* That contradicts the shape of the budget, not just its constants. Everything
|
|
20
|
+
* in the quality offer adds seconds of work per second of content — this
|
|
21
|
+
* encode, plus that decode, plus what is already committed — and these readings
|
|
22
|
+
* say two jobs that each fit alone do not fit together. The availability
|
|
23
|
+
* correction in `encode/available-share.js` does not cover it either: that subtracts
|
|
24
|
+
* the share of the machine taken by work nobody has been charged for, while
|
|
25
|
+
* this is our own work colliding with itself.
|
|
26
|
+
*
|
|
27
|
+
* So the penalty is measured rather than derived, at startup, on the host it
|
|
28
|
+
* describes — and beyond the range that was measured it does not extrapolate:
|
|
29
|
+
* it holds the largest reading and says so, because nothing here knows what a
|
|
30
|
+
* fourth job would do.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Penalties measured on this host, keyed by how many OTHER jobs were running.
|
|
35
|
+
*
|
|
36
|
+
* @typedef {Map<number, number>} ContentionPenalties
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The multiplier for a job's cost when `othersRunning` other jobs share the
|
|
41
|
+
* machine.
|
|
42
|
+
*
|
|
43
|
+
* @param {number} othersRunning
|
|
44
|
+
* @param {ContentionPenalties | null} measured
|
|
45
|
+
* @returns {{ penalty: number, measured: boolean, from: number }}
|
|
46
|
+
* `from` is the reading it came from — equal to `othersRunning` when one was
|
|
47
|
+
* measured for exactly that many, and the largest available otherwise.
|
|
48
|
+
*/
|
|
49
|
+
export function contentionPenalty(othersRunning, measured) {
|
|
50
|
+
const others = Number.isFinite(othersRunning) ? Math.max(0, Math.round(othersRunning)) : 0;
|
|
51
|
+
if (others === 0) {
|
|
52
|
+
// Alone on the machine is what every benchmark measures, so there is
|
|
53
|
+
// nothing to correct.
|
|
54
|
+
return { penalty: 1, measured: true, from: 0 };
|
|
55
|
+
}
|
|
56
|
+
if (!(measured instanceof Map) || measured.size === 0) {
|
|
57
|
+
// Nothing measured: the honest multiplier is 1, and the caller's own log
|
|
58
|
+
// says the prediction is uncorrected. Inventing a penalty would be the
|
|
59
|
+
// same mistake as inventing a fill rate.
|
|
60
|
+
return { penalty: 1, measured: false, from: 0 };
|
|
61
|
+
}
|
|
62
|
+
const exact = measured.get(others);
|
|
63
|
+
if (Number.isFinite(exact) && exact > 0) {
|
|
64
|
+
return { penalty: exact, measured: true, from: others };
|
|
65
|
+
}
|
|
66
|
+
// Beyond what was measured, hold the largest reading rather than continue the
|
|
67
|
+
// curve. Two readings say nothing about the shape past them, and a budget
|
|
68
|
+
// that extrapolates a memory bottleneck will be wrong in whichever direction
|
|
69
|
+
// it guesses.
|
|
70
|
+
let largestKey = 0;
|
|
71
|
+
let largestValue = 1;
|
|
72
|
+
for (const [key, value] of measured) {
|
|
73
|
+
if (key <= others && key > largestKey && Number.isFinite(value) && value > 0) {
|
|
74
|
+
largestKey = key;
|
|
75
|
+
largestValue = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (largestKey === 0) {
|
|
79
|
+
return { penalty: 1, measured: false, from: 0 };
|
|
80
|
+
}
|
|
81
|
+
return { penalty: largestValue, measured: true, from: largestKey };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* A cost, corrected for what else will be running.
|
|
86
|
+
*
|
|
87
|
+
* @param {number} costSecondsPerSecond - As the benchmarks priced it, alone.
|
|
88
|
+
* @param {number} othersRunning
|
|
89
|
+
* @param {ContentionPenalties | null} measured
|
|
90
|
+
* @returns {number}
|
|
91
|
+
*/
|
|
92
|
+
export function costWithContention(costSecondsPerSecond, othersRunning, measured) {
|
|
93
|
+
if (!Number.isFinite(costSecondsPerSecond) || costSecondsPerSecond <= 0) {
|
|
94
|
+
return costSecondsPerSecond;
|
|
95
|
+
}
|
|
96
|
+
return costSecondsPerSecond * contentionPenalty(othersRunning, measured).penalty;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Turn measured decode speeds into penalties.
|
|
101
|
+
*
|
|
102
|
+
* @param {number} aloneSpeed - Decode speed with the machine to itself.
|
|
103
|
+
* @param {Array<{ others: number, speed: number }>} beside - One reading per
|
|
104
|
+
* number of other jobs running.
|
|
105
|
+
* @returns {ContentionPenalties | null} Null when the alone reading is missing,
|
|
106
|
+
* since every penalty is relative to it.
|
|
107
|
+
*/
|
|
108
|
+
export function penaltiesFrom(aloneSpeed, beside) {
|
|
109
|
+
if (!Number.isFinite(aloneSpeed) || aloneSpeed <= 0) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const penalties = new Map();
|
|
113
|
+
for (const reading of Array.isArray(beside) ? beside : []) {
|
|
114
|
+
const others = Number.isFinite(reading?.others) ? Math.round(reading.others) : null;
|
|
115
|
+
const speed = Number(reading?.speed);
|
|
116
|
+
if (others === null || others <= 0 || !Number.isFinite(speed) || speed <= 0) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// Cost is the reciprocal of speed, so the penalty is the reciprocal ratio.
|
|
120
|
+
// A job that runs at half the speed costs twice as much.
|
|
121
|
+
const penalty = aloneSpeed / speed;
|
|
122
|
+
// Below 1 would mean the machine got FASTER for being busier. It happens in
|
|
123
|
+
// the noise on a fast host, and it is not a discovery — it is a reading
|
|
124
|
+
// that says there is no penalty to measure here.
|
|
125
|
+
penalties.set(others, penalty > 1 ? penalty : 1);
|
|
126
|
+
}
|
|
127
|
+
return penalties.size > 0 ? penalties : null;
|
|
128
|
+
}
|