@torrent-tv/proxy 2.87.10 → 2.87.11
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 +2186 -2181
- 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 +124 -101
- 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 +100 -100
- package/routes/api/sources/post.js +36 -36
- package/routes/api/sources/stats/get.js +132 -132
- 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 +136 -129
- package/routes/api/transcode-sessions/post.js +160 -160
- 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 +361 -361
- 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/services/encode/CoverageMap.js +428 -428
- package/services/encode/CushionReport.js +345 -345
- package/services/encode/EncodeAdmission.js +332 -332
- package/services/encode/EncodeOrchestrator.js +1217 -1217
- package/services/encode/EncodePlan.js +1366 -1366
- package/services/encode/EncodeRun.js +776 -776
- package/services/encode/EncodeRuns.js +1229 -1229
- 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 +755 -755
- package/services/encode/OutputTimes.js +579 -579
- package/services/encode/QsvEncoder.js +58 -58
- package/services/encode/Renditions.js +2184 -2162
- 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 +1110 -1083
- 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 +266 -266
- 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 +747 -747
- package/services/encode/run-costs.js +155 -155
- package/services/encode/run-inputs.js +42 -42
- package/services/encode/segment-formats/fmp4.js +437 -437
- package/services/encode/segment-formats/index.js +77 -77
- package/services/encode/segment-formats/init-compat.js +324 -324
- package/services/encode/segment-formats/mp4-boxes.js +311 -311
- 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/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 +322 -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 +1146 -1146
- package/services/server/ViewerRequests.js +703 -522
- package/services/server/WaitLedger.js +142 -142
- package/services/server/controllers/SubtitleController.js +109 -109
- package/services/server/http-responses.js +60 -60
- package/services/server/playback-readiness.js +620 -0
- package/services/server/transcode-session-files.js +325 -325
- package/services/server/wire-outputs.js +989 -983
- 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 +516 -516
- package/services/storage/piece-store/piece-lru.js +495 -495
- package/services/storage/piece-store/shared-piece-store.js +1880 -1880
- package/services/storage/returns.js +103 -103
- package/services/storage/segment-store/SegmentStore.js +1196 -1196
- package/services/storage/wire.js +175 -175
- package/services/torrent/Contents.js +324 -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/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/worker/background-fill.js +213 -213
- package/services/torrent/worker/channel.js +271 -271
- 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/resume-warm.js +107 -107
- package/services/torrent/worker/webrtc-shim.js +219 -219
- 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 +675 -657
- 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-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/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 +161 -161
- 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/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-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 +381 -381
- 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 +560 -560
- package/test/piece-store-never-refuses.test.js +153 -153
- package/test/piece-store-reservations.test.js +318 -318
- 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 +323 -0
- 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 +103 -103
- 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 +182 -182
- 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-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
package/test/link-budget.test.js
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file What a viewer's link does with an output's whole load — roadmap item
|
|
3
|
-
* 97, step 11.
|
|
4
|
-
*
|
|
5
|
-
* Pure functions over plain numbers: no session, no viewer, no clock.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import test from "node:test";
|
|
9
|
-
import assert from "node:assert/strict";
|
|
10
|
-
import {
|
|
11
|
-
admissionRank,
|
|
12
|
-
audioLoadOf,
|
|
13
|
-
LINK_SAFETY,
|
|
14
|
-
LINK_VERDICT,
|
|
15
|
-
linkCouldCarry,
|
|
16
|
-
loadOf,
|
|
17
|
-
PEAK_CLASS,
|
|
18
|
-
videoLoadForFrame,
|
|
19
|
-
videoLoadOfSpec
|
|
20
|
-
} from "../services/encode/quality/link-budget.js";
|
|
21
|
-
import { AUDIO_TRANSCODE_KBPS, maxrateKbpsFor, nominalKbpsFor, softwareRateControlFor } from "../services/encode/args.js";
|
|
22
|
-
import { outputSpec } from "./helpers/output-spec.js";
|
|
23
|
-
|
|
24
|
-
const known = (mbps) => ({ mbps, peakClass: PEAK_CLASS.KNOWN });
|
|
25
|
-
const estimated = (mbps) => ({ mbps, peakClass: PEAK_CLASS.ESTIMATED });
|
|
26
|
-
const unknown = () => ({ mbps: null, peakClass: PEAK_CLASS.UNKNOWN });
|
|
27
|
-
|
|
28
|
-
test("a copied source at its own height is its stated average — an estimate, not a bound", () => {
|
|
29
|
-
const part = videoLoadForFrame({ sourceHeight: 1080, copiesAtSource: true, sourceMbps: 3.73, encoderKind: "software" }, { width: 1920, height: 1080 });
|
|
30
|
-
assert.deepEqual(part, estimated(3.73));
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("a height the software encoder makes is bounded by the nominal limit of that height", () => {
|
|
34
|
-
const part = videoLoadForFrame({ sourceHeight: 1080, copiesAtSource: true, sourceMbps: 3.73, encoderKind: "software" }, { width: 1280, height: 720 });
|
|
35
|
-
assert.deepEqual(part, known(maxrateKbpsFor(nominalKbpsFor({ width: 1280, height: 720 })) / 1000));
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("a height a hardware encoder makes has no bound at all", () => {
|
|
39
|
-
// It is given a quality figure and no -maxrate, so there is nothing to
|
|
40
|
-
// compare a link against.
|
|
41
|
-
const part = videoLoadForFrame({ sourceHeight: 1080, copiesAtSource: false, sourceMbps: 3.73, encoderKind: "nvenc" }, { width: 1280, height: 720 });
|
|
42
|
-
assert.deepEqual(part, unknown());
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("an output's picture is read off its own rate control", () => {
|
|
46
|
-
const rateControl = softwareRateControlFor({ width: 1280, height: 720, fps: 24, capKbps: 1400 });
|
|
47
|
-
const limited = outputSpec({ transcodeVideo: true, width: 1280, height: 720, rateControl });
|
|
48
|
-
const unlimited = outputSpec({ transcodeVideo: true, width: 1280, height: 720 });
|
|
49
|
-
assert.deepEqual(videoLoadOfSpec(limited, 3.73), known(rateControl.maxrateKbps / 1000));
|
|
50
|
-
assert.deepEqual(videoLoadOfSpec(unlimited, 3.73), unknown(), "no limit, no bound");
|
|
51
|
-
assert.deepEqual(videoLoadOfSpec(outputSpec(), 3.73), estimated(3.73), "a copy is its source's average");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("a soundtrack is known when re-encoded, estimated when copied, unknown when nothing states its rate", () => {
|
|
55
|
-
assert.deepEqual(audioLoadOf({ transcode: true, bitrateKbps: null }, AUDIO_TRANSCODE_KBPS), known(AUDIO_TRANSCODE_KBPS / 1000));
|
|
56
|
-
assert.deepEqual(audioLoadOf({ transcode: false, bitrateKbps: 640 }, AUDIO_TRANSCODE_KBPS), estimated(0.64));
|
|
57
|
-
assert.deepEqual(audioLoadOf({ transcode: false, bitrateKbps: null }, AUDIO_TRANSCODE_KBPS), unknown());
|
|
58
|
-
assert.equal(audioLoadOf(null, AUDIO_TRANSCODE_KBPS), null, "no sound, no part");
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("a load is as trustworthy as its least trustworthy part", () => {
|
|
62
|
-
assert.equal(loadOf(known(3), known(0.128)).peakClass, PEAK_CLASS.KNOWN);
|
|
63
|
-
assert.equal(loadOf(known(3), estimated(0.64)).peakClass, PEAK_CLASS.ESTIMATED);
|
|
64
|
-
assert.equal(loadOf(known(3), unknown()).peakClass, PEAK_CLASS.UNKNOWN);
|
|
65
|
-
assert.equal(loadOf(known(3), unknown()).totalMbps, null, "an unknown part leaves no total");
|
|
66
|
-
assert.ok(Math.abs(loadOf(known(3), known(0.128)).totalMbps - 3.128) < 1e-9, "the sound is added to the picture");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("the sound is counted before the link's usable share is applied", () => {
|
|
70
|
-
// The picture alone fits the usable share exactly; with the soundtrack the
|
|
71
|
-
// viewer hears, it does not.
|
|
72
|
-
const link = 10;
|
|
73
|
-
const picture = known(link * LINK_SAFETY);
|
|
74
|
-
assert.equal(linkCouldCarry(link, loadOf(picture, null)).verdict, LINK_VERDICT.FITS, "without sound it would pass");
|
|
75
|
-
assert.equal(
|
|
76
|
-
linkCouldCarry(link, loadOf(picture, known(AUDIO_TRANSCODE_KBPS / 1000))).verdict,
|
|
77
|
-
LINK_VERDICT.DOES_NOT_FIT,
|
|
78
|
-
"with the 128 kbit/s soundtrack it does not"
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("a known load that passes fits and is confirmed; an estimated one is admitted and not confirmed", () => {
|
|
83
|
-
const fits = linkCouldCarry(10, loadOf(known(5), null));
|
|
84
|
-
assert.equal(fits.verdict, LINK_VERDICT.FITS);
|
|
85
|
-
assert.equal(fits.confirmed, true);
|
|
86
|
-
const byEstimate = linkCouldCarry(10, loadOf(estimated(5), null));
|
|
87
|
-
assert.equal(byEstimate.verdict, LINK_VERDICT.ESTIMATED_TO_FIT);
|
|
88
|
-
assert.equal(byEstimate.admitted, true);
|
|
89
|
-
assert.equal(byEstimate.confirmed, false, "an average is not a bound");
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test("an unknown load is refused against a measured link, and admitted while nothing measured it", () => {
|
|
93
|
-
const measured = linkCouldCarry(50, loadOf(unknown(), null));
|
|
94
|
-
assert.equal(measured.verdict, LINK_VERDICT.NO_SAFE_BOUND);
|
|
95
|
-
assert.equal(measured.admitted, false, "there is no number to compare, however fast the link");
|
|
96
|
-
for (const unmeasured of [null, 0, Number.NaN]) {
|
|
97
|
-
const answer = linkCouldCarry(unmeasured, loadOf(unknown(), null));
|
|
98
|
-
assert.equal(answer.verdict, LINK_VERDICT.NO_MEASUREMENT);
|
|
99
|
-
assert.equal(answer.admitted, true, "the link gave no ground to refuse");
|
|
100
|
-
assert.equal(answer.confirmed, false);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("a bound ranks before an average, and a refusal ranks nowhere", () => {
|
|
105
|
-
const knownAnswer = linkCouldCarry(null, loadOf(known(5), null));
|
|
106
|
-
const estimatedAnswer = linkCouldCarry(null, loadOf(estimated(5), null));
|
|
107
|
-
const unknownAnswer = linkCouldCarry(null, loadOf(unknown(), null));
|
|
108
|
-
assert.ok(admissionRank(knownAnswer) > admissionRank(estimatedAnswer));
|
|
109
|
-
assert.ok(admissionRank(estimatedAnswer) > admissionRank(unknownAnswer));
|
|
110
|
-
assert.equal(admissionRank(linkCouldCarry(1, loadOf(known(5), null))), 0);
|
|
111
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file What a viewer's link does with an output's whole load — roadmap item
|
|
3
|
+
* 97, step 11.
|
|
4
|
+
*
|
|
5
|
+
* Pure functions over plain numbers: no session, no viewer, no clock.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import {
|
|
11
|
+
admissionRank,
|
|
12
|
+
audioLoadOf,
|
|
13
|
+
LINK_SAFETY,
|
|
14
|
+
LINK_VERDICT,
|
|
15
|
+
linkCouldCarry,
|
|
16
|
+
loadOf,
|
|
17
|
+
PEAK_CLASS,
|
|
18
|
+
videoLoadForFrame,
|
|
19
|
+
videoLoadOfSpec
|
|
20
|
+
} from "../services/encode/quality/link-budget.js";
|
|
21
|
+
import { AUDIO_TRANSCODE_KBPS, maxrateKbpsFor, nominalKbpsFor, softwareRateControlFor } from "../services/encode/args.js";
|
|
22
|
+
import { outputSpec } from "./helpers/output-spec.js";
|
|
23
|
+
|
|
24
|
+
const known = (mbps) => ({ mbps, peakClass: PEAK_CLASS.KNOWN });
|
|
25
|
+
const estimated = (mbps) => ({ mbps, peakClass: PEAK_CLASS.ESTIMATED });
|
|
26
|
+
const unknown = () => ({ mbps: null, peakClass: PEAK_CLASS.UNKNOWN });
|
|
27
|
+
|
|
28
|
+
test("a copied source at its own height is its stated average — an estimate, not a bound", () => {
|
|
29
|
+
const part = videoLoadForFrame({ sourceHeight: 1080, copiesAtSource: true, sourceMbps: 3.73, encoderKind: "software" }, { width: 1920, height: 1080 });
|
|
30
|
+
assert.deepEqual(part, estimated(3.73));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("a height the software encoder makes is bounded by the nominal limit of that height", () => {
|
|
34
|
+
const part = videoLoadForFrame({ sourceHeight: 1080, copiesAtSource: true, sourceMbps: 3.73, encoderKind: "software" }, { width: 1280, height: 720 });
|
|
35
|
+
assert.deepEqual(part, known(maxrateKbpsFor(nominalKbpsFor({ width: 1280, height: 720 })) / 1000));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("a height a hardware encoder makes has no bound at all", () => {
|
|
39
|
+
// It is given a quality figure and no -maxrate, so there is nothing to
|
|
40
|
+
// compare a link against.
|
|
41
|
+
const part = videoLoadForFrame({ sourceHeight: 1080, copiesAtSource: false, sourceMbps: 3.73, encoderKind: "nvenc" }, { width: 1280, height: 720 });
|
|
42
|
+
assert.deepEqual(part, unknown());
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("an output's picture is read off its own rate control", () => {
|
|
46
|
+
const rateControl = softwareRateControlFor({ width: 1280, height: 720, fps: 24, capKbps: 1400 });
|
|
47
|
+
const limited = outputSpec({ transcodeVideo: true, width: 1280, height: 720, rateControl });
|
|
48
|
+
const unlimited = outputSpec({ transcodeVideo: true, width: 1280, height: 720 });
|
|
49
|
+
assert.deepEqual(videoLoadOfSpec(limited, 3.73), known(rateControl.maxrateKbps / 1000));
|
|
50
|
+
assert.deepEqual(videoLoadOfSpec(unlimited, 3.73), unknown(), "no limit, no bound");
|
|
51
|
+
assert.deepEqual(videoLoadOfSpec(outputSpec(), 3.73), estimated(3.73), "a copy is its source's average");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("a soundtrack is known when re-encoded, estimated when copied, unknown when nothing states its rate", () => {
|
|
55
|
+
assert.deepEqual(audioLoadOf({ transcode: true, bitrateKbps: null }, AUDIO_TRANSCODE_KBPS), known(AUDIO_TRANSCODE_KBPS / 1000));
|
|
56
|
+
assert.deepEqual(audioLoadOf({ transcode: false, bitrateKbps: 640 }, AUDIO_TRANSCODE_KBPS), estimated(0.64));
|
|
57
|
+
assert.deepEqual(audioLoadOf({ transcode: false, bitrateKbps: null }, AUDIO_TRANSCODE_KBPS), unknown());
|
|
58
|
+
assert.equal(audioLoadOf(null, AUDIO_TRANSCODE_KBPS), null, "no sound, no part");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("a load is as trustworthy as its least trustworthy part", () => {
|
|
62
|
+
assert.equal(loadOf(known(3), known(0.128)).peakClass, PEAK_CLASS.KNOWN);
|
|
63
|
+
assert.equal(loadOf(known(3), estimated(0.64)).peakClass, PEAK_CLASS.ESTIMATED);
|
|
64
|
+
assert.equal(loadOf(known(3), unknown()).peakClass, PEAK_CLASS.UNKNOWN);
|
|
65
|
+
assert.equal(loadOf(known(3), unknown()).totalMbps, null, "an unknown part leaves no total");
|
|
66
|
+
assert.ok(Math.abs(loadOf(known(3), known(0.128)).totalMbps - 3.128) < 1e-9, "the sound is added to the picture");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("the sound is counted before the link's usable share is applied", () => {
|
|
70
|
+
// The picture alone fits the usable share exactly; with the soundtrack the
|
|
71
|
+
// viewer hears, it does not.
|
|
72
|
+
const link = 10;
|
|
73
|
+
const picture = known(link * LINK_SAFETY);
|
|
74
|
+
assert.equal(linkCouldCarry(link, loadOf(picture, null)).verdict, LINK_VERDICT.FITS, "without sound it would pass");
|
|
75
|
+
assert.equal(
|
|
76
|
+
linkCouldCarry(link, loadOf(picture, known(AUDIO_TRANSCODE_KBPS / 1000))).verdict,
|
|
77
|
+
LINK_VERDICT.DOES_NOT_FIT,
|
|
78
|
+
"with the 128 kbit/s soundtrack it does not"
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("a known load that passes fits and is confirmed; an estimated one is admitted and not confirmed", () => {
|
|
83
|
+
const fits = linkCouldCarry(10, loadOf(known(5), null));
|
|
84
|
+
assert.equal(fits.verdict, LINK_VERDICT.FITS);
|
|
85
|
+
assert.equal(fits.confirmed, true);
|
|
86
|
+
const byEstimate = linkCouldCarry(10, loadOf(estimated(5), null));
|
|
87
|
+
assert.equal(byEstimate.verdict, LINK_VERDICT.ESTIMATED_TO_FIT);
|
|
88
|
+
assert.equal(byEstimate.admitted, true);
|
|
89
|
+
assert.equal(byEstimate.confirmed, false, "an average is not a bound");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("an unknown load is refused against a measured link, and admitted while nothing measured it", () => {
|
|
93
|
+
const measured = linkCouldCarry(50, loadOf(unknown(), null));
|
|
94
|
+
assert.equal(measured.verdict, LINK_VERDICT.NO_SAFE_BOUND);
|
|
95
|
+
assert.equal(measured.admitted, false, "there is no number to compare, however fast the link");
|
|
96
|
+
for (const unmeasured of [null, 0, Number.NaN]) {
|
|
97
|
+
const answer = linkCouldCarry(unmeasured, loadOf(unknown(), null));
|
|
98
|
+
assert.equal(answer.verdict, LINK_VERDICT.NO_MEASUREMENT);
|
|
99
|
+
assert.equal(answer.admitted, true, "the link gave no ground to refuse");
|
|
100
|
+
assert.equal(answer.confirmed, false);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("a bound ranks before an average, and a refusal ranks nowhere", () => {
|
|
105
|
+
const knownAnswer = linkCouldCarry(null, loadOf(known(5), null));
|
|
106
|
+
const estimatedAnswer = linkCouldCarry(null, loadOf(estimated(5), null));
|
|
107
|
+
const unknownAnswer = linkCouldCarry(null, loadOf(unknown(), null));
|
|
108
|
+
assert.ok(admissionRank(knownAnswer) > admissionRank(estimatedAnswer));
|
|
109
|
+
assert.ok(admissionRank(estimatedAnswer) > admissionRank(unknownAnswer));
|
|
110
|
+
assert.equal(admissionRank(linkCouldCarry(1, loadOf(known(5), null))), 0);
|
|
111
|
+
});
|
package/test/link-probe.test.js
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file The route that hands a browser bytes to time its link with.
|
|
3
|
-
*
|
|
4
|
-
* Only this end's half. How big an ask should be is derived on the page, from
|
|
5
|
-
* what its last ask measured, and is checked where that function lives — a copy
|
|
6
|
-
* of it here would be two owners of one rule, which is the fault this
|
|
7
|
-
* repository keeps recording.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import assert from "node:assert/strict";
|
|
11
|
-
import test from "node:test";
|
|
12
|
-
|
|
13
|
-
import { handleApiLinkProbeGet, MAX_LINK_PROBE_BYTES } from "../routes/api/link-probe/get.js";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* A reply that records what it was given.
|
|
17
|
-
*
|
|
18
|
-
* @returns {{ code: (n: number) => object, header: () => object, send: (b: unknown) => object, status: number | null, body: unknown }}
|
|
19
|
-
*/
|
|
20
|
-
function fakeReply() {
|
|
21
|
-
const reply = {
|
|
22
|
-
status: /** @type {number | null} */ (null),
|
|
23
|
-
body: /** @type {unknown} */ (null),
|
|
24
|
-
code(n) {
|
|
25
|
-
reply.status = n;
|
|
26
|
-
return reply;
|
|
27
|
-
},
|
|
28
|
-
header() {
|
|
29
|
-
return reply;
|
|
30
|
-
},
|
|
31
|
-
send(body) {
|
|
32
|
-
reply.body = body;
|
|
33
|
-
return reply;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
return reply;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
test("the route answers exactly what was asked for, up to its own ceiling", async () => {
|
|
42
|
-
const small = fakeReply();
|
|
43
|
-
await handleApiLinkProbeGet({ query: { bytes: "65536" } }, small);
|
|
44
|
-
assert.equal(small.status, 200);
|
|
45
|
-
assert.equal(/** @type {Buffer} */ (small.body).length, 65536);
|
|
46
|
-
|
|
47
|
-
const huge = fakeReply();
|
|
48
|
-
await handleApiLinkProbeGet({ query: { bytes: "999999999" } }, huge);
|
|
49
|
-
assert.equal(/** @type {Buffer} */ (huge.body).length, MAX_LINK_PROBE_BYTES);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("the route refuses an ask that is not a size", async () => {
|
|
53
|
-
const reply = fakeReply();
|
|
54
|
-
await handleApiLinkProbeGet({ query: { bytes: "none" } }, reply);
|
|
55
|
-
assert.equal(reply.status, 400);
|
|
56
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file The route that hands a browser bytes to time its link with.
|
|
3
|
+
*
|
|
4
|
+
* Only this end's half. How big an ask should be is derived on the page, from
|
|
5
|
+
* what its last ask measured, and is checked where that function lives — a copy
|
|
6
|
+
* of it here would be two owners of one rule, which is the fault this
|
|
7
|
+
* repository keeps recording.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
|
|
13
|
+
import { handleApiLinkProbeGet, MAX_LINK_PROBE_BYTES } from "../routes/api/link-probe/get.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A reply that records what it was given.
|
|
17
|
+
*
|
|
18
|
+
* @returns {{ code: (n: number) => object, header: () => object, send: (b: unknown) => object, status: number | null, body: unknown }}
|
|
19
|
+
*/
|
|
20
|
+
function fakeReply() {
|
|
21
|
+
const reply = {
|
|
22
|
+
status: /** @type {number | null} */ (null),
|
|
23
|
+
body: /** @type {unknown} */ (null),
|
|
24
|
+
code(n) {
|
|
25
|
+
reply.status = n;
|
|
26
|
+
return reply;
|
|
27
|
+
},
|
|
28
|
+
header() {
|
|
29
|
+
return reply;
|
|
30
|
+
},
|
|
31
|
+
send(body) {
|
|
32
|
+
reply.body = body;
|
|
33
|
+
return reply;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return reply;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
test("the route answers exactly what was asked for, up to its own ceiling", async () => {
|
|
42
|
+
const small = fakeReply();
|
|
43
|
+
await handleApiLinkProbeGet({ query: { bytes: "65536" } }, small);
|
|
44
|
+
assert.equal(small.status, 200);
|
|
45
|
+
assert.equal(/** @type {Buffer} */ (small.body).length, 65536);
|
|
46
|
+
|
|
47
|
+
const huge = fakeReply();
|
|
48
|
+
await handleApiLinkProbeGet({ query: { bytes: "999999999" } }, huge);
|
|
49
|
+
assert.equal(/** @type {Buffer} */ (huge.body).length, MAX_LINK_PROBE_BYTES);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("the route refuses an ask that is not a size", async () => {
|
|
53
|
+
const reply = fakeReply();
|
|
54
|
+
await handleApiLinkProbeGet({ query: { bytes: "none" } }, reply);
|
|
55
|
+
assert.equal(reply.status, 400);
|
|
56
|
+
});
|