@simulatte/doppler 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -0
- package/README.md +25 -17
- package/package.json +20 -4
- package/src/adapters/adapter-registry.js +12 -1
- package/src/adapters/lora-loader.js +23 -6
- package/src/bridge/extension-client.d.ts +5 -0
- package/src/bridge/extension-client.js +40 -0
- package/src/bridge/index.d.ts +2 -1
- package/src/bridge/index.js +6 -4
- package/src/browser/browser-converter.js +26 -1
- package/src/browser/file-picker.js +6 -0
- package/src/browser/safetensors-parser-browser.js +84 -1
- package/src/browser/shard-io-browser.js +2 -2
- package/src/browser/tensor-source-download.js +8 -2
- package/src/browser/tensor-source-http.d.ts +1 -0
- package/src/browser/tensor-source-http.js +5 -1
- package/src/client/doppler-api.browser.js +20 -4
- package/src/client/doppler-api.js +19 -3
- package/src/client/doppler-provider/generation.js +12 -0
- package/src/client/doppler-provider/model-manager.d.ts +10 -0
- package/src/client/doppler-provider/model-manager.js +91 -19
- package/src/client/doppler-provider/source-runtime.d.ts +2 -1
- package/src/client/doppler-provider/source-runtime.js +132 -13
- package/src/client/doppler-registry.json +8 -7
- package/src/config/backward-registry-loader.js +17 -2
- package/src/config/execution-v0-contract-check.js +113 -15
- package/src/config/kernel-path-contract-check.js +57 -29
- package/src/config/kernel-path-loader.js +5 -36
- package/src/config/kernels/kernel-ref-digests.js +39 -39
- package/src/config/kernels/registry.js +14 -1
- package/src/config/kernels/registry.json +49 -7
- package/src/config/loader.d.ts +1 -1
- package/src/config/loader.js +43 -4
- package/src/config/merge-contract-check.js +59 -4
- package/src/config/merge-helpers.js +128 -7
- package/src/config/merge.d.ts +1 -0
- package/src/config/merge.js +28 -0
- package/src/config/param-validator.js +47 -2
- package/src/config/presets/kernel-paths/{gemma2-q4k-dequant-f32a.json → gemma2-q4k-dequant-f32a-nosubgroups.json} +3 -3
- package/src/config/presets/kernel-paths/gemma3-f16-fused-f32a-online-streamingprefill.json +223 -0
- package/src/config/presets/kernel-paths/{gemma3-q4k-dequant-f32a.json → gemma3-q4k-dequant-f32a-nosubgroups.json} +3 -3
- package/src/config/presets/kernel-paths/registry.json +29 -8
- package/src/config/presets/models/gemma2.json +2 -2
- package/src/config/presets/models/qwen3.json +9 -2
- package/src/config/presets/models/transformer.json +5 -0
- package/src/config/presets/runtime/experiments/bench/gemma3-bench-q4k.json +1 -1
- package/src/config/presets/runtime/experiments/debug/gemma3-debug-q4k.json +1 -1
- package/src/config/presets/runtime/experiments/verify/gemma3-verify.json +1 -1
- package/src/config/presets/runtime/kernels/dequant-f16-q4k.json +6 -13
- package/src/config/presets/runtime/kernels/dequant-f32-q4k.json +6 -13
- package/src/config/presets/runtime/kernels/embeddinggemma-q4k-dequant-f32a.json +37 -0
- package/src/config/presets/runtime/kernels/fused-q4k.json +6 -13
- package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f16a.json +33 -0
- package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f32a-nosubgroups.json +33 -0
- package/src/config/presets/runtime/kernels/gemma2-q4k-fused-f32a.json +33 -0
- package/src/config/presets/runtime/kernels/safe-q4k.json +6 -13
- package/src/config/presets/runtime/platform/metal-apple-q4k.json +1 -1
- package/src/config/required-inference-fields-contract-check.js +6 -0
- package/src/config/runtime.js +6 -1
- package/src/config/schema/debug.schema.d.ts +5 -0
- package/src/config/schema/doppler.schema.js +16 -21
- package/src/config/schema/inference-defaults.schema.js +6 -3
- package/src/config/schema/inference.schema.d.ts +9 -0
- package/src/config/schema/kernel-path.schema.d.ts +11 -1
- package/src/config/schema/kernel-thresholds.schema.js +12 -4
- package/src/config/schema/manifest.schema.d.ts +8 -1
- package/src/config/schema/manifest.schema.js +19 -3
- package/src/config/training-defaults.js +30 -22
- package/src/converter/conversion-plan.js +94 -9
- package/src/converter/core.d.ts +7 -0
- package/src/converter/core.js +14 -9
- package/src/converter/execution-v0-manifest.js +4 -1
- package/src/converter/index.d.ts +1 -0
- package/src/converter/index.js +1 -0
- package/src/converter/manifest-inference.js +43 -12
- package/src/converter/parsers/diffusion.js +0 -3
- package/src/converter/quantization-info.js +35 -15
- package/src/converter/rope-config.js +42 -0
- package/src/converter/shard-packer.d.ts +1 -1
- package/src/converter/shard-packer.js +4 -1
- package/src/debug/config.js +123 -11
- package/src/debug/signals.js +7 -1
- package/src/debug/tensor.d.ts +2 -0
- package/src/debug/tensor.js +13 -2
- package/src/distribution/p2p-control-plane.js +52 -12
- package/src/distribution/p2p-observability.js +43 -7
- package/src/distribution/p2p-webrtc-browser.js +20 -0
- package/src/distribution/shard-delivery.js +77 -26
- package/src/formats/gguf/types.js +33 -16
- package/src/formats/rdrr/groups.d.ts +12 -4
- package/src/formats/rdrr/groups.js +3 -6
- package/src/formats/rdrr/parsing.js +39 -2
- package/src/formats/rdrr/types.d.ts +2 -1
- package/src/gpu/command-recorder.js +86 -61
- package/src/gpu/device.d.ts +1 -0
- package/src/gpu/device.js +131 -19
- package/src/gpu/kernel-tuner/benchmarks.js +326 -316
- package/src/gpu/kernel-tuner/cache.js +71 -4
- package/src/gpu/kernel-tuner/tuner.js +22 -4
- package/src/gpu/kernels/attention.js +113 -34
- package/src/gpu/kernels/backward/adam.js +62 -58
- package/src/gpu/kernels/backward/attention_backward.js +257 -169
- package/src/gpu/kernels/backward/conv2d_backward.js +14 -1
- package/src/gpu/kernels/bias_add.wgsl +8 -6
- package/src/gpu/kernels/bias_add_f16.wgsl +8 -5
- package/src/gpu/kernels/cast.js +191 -149
- package/src/gpu/kernels/check-stop.js +33 -44
- package/src/gpu/kernels/conv2d.js +27 -17
- package/src/gpu/kernels/conv2d.wgsl +7 -8
- package/src/gpu/kernels/conv2d_f16.wgsl +7 -8
- package/src/gpu/kernels/cross_entropy_loss.js +21 -15
- package/src/gpu/kernels/depthwise_conv2d.js +37 -26
- package/src/gpu/kernels/depthwise_conv2d.wgsl +6 -9
- package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +6 -9
- package/src/gpu/kernels/dequant.js +178 -126
- package/src/gpu/kernels/energy.d.ts +3 -21
- package/src/gpu/kernels/energy.js +111 -88
- package/src/gpu/kernels/feature-check.js +1 -1
- package/src/gpu/kernels/fused_ffn.js +84 -65
- package/src/gpu/kernels/fused_matmul_residual.js +56 -33
- package/src/gpu/kernels/fused_matmul_rmsnorm.js +62 -45
- package/src/gpu/kernels/gather.js +33 -15
- package/src/gpu/kernels/gelu.js +19 -11
- package/src/gpu/kernels/grouped_pointwise_conv2d.js +34 -23
- package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +6 -9
- package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +6 -9
- package/src/gpu/kernels/groupnorm.js +34 -23
- package/src/gpu/kernels/kv-quantize.js +5 -2
- package/src/gpu/kernels/layernorm.js +35 -19
- package/src/gpu/kernels/logit-merge.js +5 -3
- package/src/gpu/kernels/matmul.js +83 -39
- package/src/gpu/kernels/modulate.js +23 -15
- package/src/gpu/kernels/moe.js +221 -175
- package/src/gpu/kernels/pixel_shuffle.js +22 -14
- package/src/gpu/kernels/pixel_shuffle.wgsl +4 -5
- package/src/gpu/kernels/pixel_shuffle_f16.wgsl +4 -5
- package/src/gpu/kernels/relu.js +31 -10
- package/src/gpu/kernels/relu.wgsl +2 -1
- package/src/gpu/kernels/relu_f16.wgsl +2 -1
- package/src/gpu/kernels/repeat_channels.js +25 -17
- package/src/gpu/kernels/repeat_channels.wgsl +4 -5
- package/src/gpu/kernels/repeat_channels_f16.wgsl +4 -5
- package/src/gpu/kernels/residual.js +69 -23
- package/src/gpu/kernels/residual.wgsl +6 -3
- package/src/gpu/kernels/residual_f16.wgsl +2 -1
- package/src/gpu/kernels/residual_f16_vec4.wgsl +2 -1
- package/src/gpu/kernels/residual_vec4.wgsl +2 -1
- package/src/gpu/kernels/rmsnorm.js +96 -28
- package/src/gpu/kernels/rmsnorm.wgsl +14 -6
- package/src/gpu/kernels/rmsnorm_f16.wgsl +10 -2
- package/src/gpu/kernels/rope.d.ts +2 -0
- package/src/gpu/kernels/rope.js +14 -1
- package/src/gpu/kernels/rope.wgsl +56 -40
- package/src/gpu/kernels/sample.js +27 -38
- package/src/gpu/kernels/sana_linear_attention.js +19 -12
- package/src/gpu/kernels/sana_linear_attention_apply.wgsl +4 -5
- package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +4 -5
- package/src/gpu/kernels/sana_linear_attention_summary.wgsl +4 -0
- package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +4 -0
- package/src/gpu/kernels/scale.js +18 -11
- package/src/gpu/kernels/shader-cache.js +4 -2
- package/src/gpu/kernels/silu.d.ts +1 -0
- package/src/gpu/kernels/silu.js +148 -82
- package/src/gpu/kernels/silu.wgsl +19 -9
- package/src/gpu/kernels/silu_f16.wgsl +19 -9
- package/src/gpu/kernels/softmax.js +44 -25
- package/src/gpu/kernels/split_qkv.js +23 -13
- package/src/gpu/kernels/transpose.js +31 -10
- package/src/gpu/kernels/transpose.wgsl +6 -5
- package/src/gpu/kernels/upsample2d.js +22 -13
- package/src/gpu/kernels/upsample2d.wgsl +6 -9
- package/src/gpu/kernels/upsample2d_f16.wgsl +6 -9
- package/src/gpu/kernels/utils.js +35 -13
- package/src/gpu/partitioned-buffer-pool.js +10 -2
- package/src/gpu/perf-guards.js +2 -9
- package/src/gpu/profiler.js +27 -22
- package/src/gpu/readback-utils.d.ts +16 -0
- package/src/gpu/readback-utils.js +41 -0
- package/src/gpu/submit-tracker.js +13 -0
- package/src/gpu/uniform-cache.d.ts +1 -0
- package/src/gpu/uniform-cache.js +30 -9
- package/src/hotswap/intent-bundle.js +6 -0
- package/src/hotswap/manifest.d.ts +10 -1
- package/src/hotswap/manifest.js +12 -2
- package/src/hotswap/runtime.js +30 -8
- package/src/index-browser.d.ts +44 -0
- package/src/index-browser.js +14 -0
- package/src/inference/browser-harness-contract-helpers.d.ts +5 -0
- package/src/inference/browser-harness-contract-helpers.js +28 -0
- package/src/inference/browser-harness-diffusion-energy-suites.d.ts +2 -0
- package/src/inference/browser-harness-diffusion-energy-suites.js +269 -0
- package/src/inference/browser-harness-model-helpers.d.ts +16 -0
- package/src/inference/browser-harness-model-helpers.js +217 -0
- package/src/inference/browser-harness-report-helpers.d.ts +7 -0
- package/src/inference/browser-harness-report-helpers.js +42 -0
- package/src/inference/browser-harness-runtime-helpers.d.ts +61 -0
- package/src/inference/browser-harness-runtime-helpers.js +415 -0
- package/src/inference/browser-harness-suite-helpers.d.ts +28 -0
- package/src/inference/browser-harness-suite-helpers.js +268 -0
- package/src/inference/browser-harness-text-helpers.d.ts +27 -0
- package/src/inference/browser-harness-text-helpers.js +788 -0
- package/src/inference/browser-harness.d.ts +6 -0
- package/src/inference/browser-harness.js +130 -1950
- package/src/inference/kv-cache/base.js +140 -94
- package/src/inference/kv-cache/tiered.js +5 -3
- package/src/inference/moe-router.js +88 -56
- package/src/inference/multi-model-network.js +5 -3
- package/src/inference/network-evolution.d.ts +11 -2
- package/src/inference/network-evolution.js +20 -21
- package/src/inference/pipelines/context.d.ts +3 -0
- package/src/inference/pipelines/context.js +142 -2
- package/src/inference/pipelines/diffusion/helpers.js +7 -2
- package/src/inference/pipelines/diffusion/pipeline.js +17 -7
- package/src/inference/pipelines/diffusion/sd3-transformer.js +10 -10
- package/src/inference/pipelines/diffusion/text-encoder-gpu.d.ts +5 -0
- package/src/inference/pipelines/diffusion/text-encoder-gpu.js +27 -15
- package/src/inference/pipelines/diffusion/vae.js +3 -7
- package/src/inference/pipelines/energy/pipeline.js +27 -21
- package/src/inference/pipelines/energy/quintel.d.ts +5 -0
- package/src/inference/pipelines/energy/quintel.js +11 -0
- package/src/inference/pipelines/energy-head/row-head-pipeline.js +17 -13
- package/src/inference/pipelines/structured/json-head-pipeline.js +26 -11
- package/src/inference/pipelines/text/attention/projections.js +151 -101
- package/src/inference/pipelines/text/attention/record.js +73 -10
- package/src/inference/pipelines/text/attention/run.js +73 -10
- package/src/inference/pipelines/text/chat-format.js +25 -1
- package/src/inference/pipelines/text/config.d.ts +4 -0
- package/src/inference/pipelines/text/config.js +71 -5
- package/src/inference/pipelines/text/embed.js +2 -8
- package/src/inference/pipelines/text/execution-plan.js +64 -50
- package/src/inference/pipelines/text/execution-v0-contract-helpers.d.ts +59 -0
- package/src/inference/pipelines/text/execution-v0-contract-helpers.js +937 -0
- package/src/inference/pipelines/text/execution-v0-runtime-builders.d.ts +15 -0
- package/src/inference/pipelines/text/execution-v0-runtime-builders.js +279 -0
- package/src/inference/pipelines/text/execution-v0.js +78 -1002
- package/src/inference/pipelines/text/ffn/standard.js +3 -0
- package/src/inference/pipelines/text/generator-steps.d.ts +46 -0
- package/src/inference/pipelines/text/generator-steps.js +298 -207
- package/src/inference/pipelines/text/generator.js +6 -23
- package/src/inference/pipelines/text/init.d.ts +4 -0
- package/src/inference/pipelines/text/init.js +134 -29
- package/src/inference/pipelines/text/kernel-path-auto-select.js +2 -0
- package/src/inference/pipelines/text/kernel-trace.d.ts +2 -0
- package/src/inference/pipelines/text/kernel-trace.js +6 -0
- package/src/inference/pipelines/text/layer.js +14 -9
- package/src/inference/pipelines/text/linear-attention.d.ts +10 -0
- package/src/inference/pipelines/text/linear-attention.js +80 -6
- package/src/inference/pipelines/text/logits/gpu.js +10 -5
- package/src/inference/pipelines/text/logits/index.js +10 -11
- package/src/inference/pipelines/text/logits/utils.d.ts +7 -0
- package/src/inference/pipelines/text/logits/utils.js +9 -0
- package/src/inference/pipelines/text/lora-apply.js +50 -32
- package/src/inference/pipelines/text/model-load.js +279 -104
- package/src/inference/pipelines/text/moe-cache.js +5 -4
- package/src/inference/pipelines/text/moe-cpu-gptoss.js +74 -69
- package/src/inference/pipelines/text/moe-cpu.js +42 -38
- package/src/inference/pipelines/text/moe-gpu.js +110 -86
- package/src/inference/pipelines/text/ops.js +90 -90
- package/src/inference/pipelines/text/probes.js +9 -9
- package/src/inference/pipelines/text/weights.js +17 -7
- package/src/inference/pipelines/text.js +17 -1
- package/src/inference/speculative.d.ts +2 -2
- package/src/inference/speculative.js +4 -18
- package/src/inference/test-harness.d.ts +1 -1
- package/src/inference/test-harness.js +15 -5
- package/src/inference/tokenizer.d.ts +0 -5
- package/src/inference/tokenizer.js +4 -23
- package/src/inference/tokenizers/bpe.js +9 -0
- package/src/inference/tokenizers/bundled.js +176 -33
- package/src/inference/tokenizers/sentencepiece.js +12 -0
- package/src/loader/doppler-loader.js +38 -22
- package/src/loader/dtype-utils.js +3 -44
- package/src/loader/embedding-loader.js +7 -3
- package/src/loader/experts/expert-cache.js +13 -6
- package/src/loader/experts/expert-loader.js +10 -6
- package/src/loader/final-weights-loader.js +8 -4
- package/src/loader/layer-loader.js +2 -1
- package/src/loader/loader-state.js +2 -2
- package/src/loader/memory-monitor.js +8 -0
- package/src/loader/multi-model-loader.d.ts +14 -0
- package/src/loader/multi-model-loader.js +70 -24
- package/src/loader/shard-cache.js +81 -12
- package/src/loader/shard-resolver.js +25 -3
- package/src/loader/tensors/tensor-loader.js +209 -144
- package/src/loader/tensors/tensor-reader.js +76 -19
- package/src/loader/weight-downcast.js +1 -1
- package/src/memory/buffer-pool.d.ts +9 -1
- package/src/memory/buffer-pool.js +109 -44
- package/src/memory/unified-detect.js +1 -1
- package/src/rules/inference/kernel-path.rules.json +24 -8
- package/src/rules/rule-registry.js +25 -1
- package/src/rules/tooling/command-runtime.rules.json +18 -0
- package/src/storage/backends/opfs-store.js +68 -24
- package/src/storage/downloader.js +364 -83
- package/src/storage/index.d.ts +3 -0
- package/src/storage/index.js +3 -0
- package/src/storage/preflight.d.ts +2 -2
- package/src/storage/preflight.js +24 -2
- package/src/storage/quickstart-downloader.js +11 -5
- package/src/storage/registry.js +10 -4
- package/src/storage/reports.js +1 -1
- package/src/storage/shard-manager.d.ts +15 -1
- package/src/storage/shard-manager.js +51 -3
- package/src/storage/source-artifact-store.d.ts +52 -0
- package/src/storage/source-artifact-store.js +234 -0
- package/src/tooling/command-api-constants.d.ts +9 -0
- package/src/tooling/command-api-constants.js +9 -0
- package/src/tooling/command-api-family-normalizers.d.ts +9 -0
- package/src/tooling/command-api-family-normalizers.js +343 -0
- package/src/tooling/command-api-helpers.d.ts +25 -0
- package/src/tooling/command-api-helpers.js +262 -0
- package/src/tooling/command-api.d.ts +27 -1
- package/src/tooling/command-api.js +26 -473
- package/src/tooling/command-envelope.js +4 -1
- package/src/tooling/command-runner-shared.js +52 -18
- package/src/tooling/lean-execution-contract.js +150 -3
- package/src/tooling/node-browser-command-runner.d.ts +4 -0
- package/src/tooling/node-browser-command-runner.js +218 -273
- package/src/tooling/node-command-runner.js +44 -3
- package/src/tooling/node-converter.js +27 -1
- package/src/tooling/node-source-runtime.d.ts +1 -1
- package/src/tooling/node-source-runtime.js +84 -3
- package/src/tooling/node-webgpu.js +30 -105
- package/src/tooling/opfs-cache.js +21 -4
- package/src/tooling/runtime-input-composition.d.ts +38 -0
- package/src/tooling/runtime-input-composition.js +86 -0
- package/src/tooling/source-runtime-bundle.d.ts +40 -5
- package/src/tooling/source-runtime-bundle.js +261 -34
- package/src/tooling/source-runtime-materializer.d.ts +6 -0
- package/src/tooling/source-runtime-materializer.js +93 -0
- package/src/training/attention-backward.js +32 -17
- package/src/training/autograd.js +80 -52
- package/src/training/checkpoint-watch.d.ts +8 -0
- package/src/training/checkpoint-watch.js +139 -0
- package/src/training/checkpoint.d.ts +6 -1
- package/src/training/checkpoint.js +46 -7
- package/src/training/clip.js +2 -1
- package/src/training/datasets/token-batch.js +20 -8
- package/src/training/distillation/artifacts.d.ts +71 -0
- package/src/training/distillation/artifacts.js +132 -0
- package/src/training/distillation/checkpoint-watch.d.ts +10 -0
- package/src/training/distillation/checkpoint-watch.js +58 -0
- package/src/training/distillation/dataset.d.ts +59 -0
- package/src/training/distillation/dataset.js +337 -0
- package/src/training/distillation/eval.d.ts +34 -0
- package/src/training/distillation/eval.js +310 -0
- package/src/training/distillation/index.d.ts +29 -0
- package/src/training/distillation/index.js +29 -0
- package/src/training/distillation/runtime.d.ts +20 -0
- package/src/training/distillation/runtime.js +121 -0
- package/src/training/distillation/scoreboard.d.ts +6 -0
- package/src/training/distillation/scoreboard.js +8 -0
- package/src/training/distillation/stage-a.d.ts +45 -0
- package/src/training/distillation/stage-a.js +338 -0
- package/src/training/distillation/stage-b.d.ts +24 -0
- package/src/training/distillation/stage-b.js +20 -0
- package/src/training/distillation/student-fixture.d.ts +22 -0
- package/src/training/distillation/student-fixture.js +846 -0
- package/src/training/distillation/suite-data.d.ts +45 -0
- package/src/training/distillation/suite-data.js +189 -0
- package/src/training/index.d.ts +10 -0
- package/src/training/index.js +10 -0
- package/src/training/lora-pipeline.d.ts +40 -0
- package/src/training/lora-pipeline.js +793 -0
- package/src/training/lora.js +26 -12
- package/src/training/loss.js +5 -6
- package/src/training/objectives/cross_entropy.js +2 -5
- package/src/training/objectives/distill_kd.js +4 -8
- package/src/training/objectives/distill_triplet.js +4 -8
- package/src/training/objectives/ul_stage2_base.js +4 -8
- package/src/training/operator-artifacts.d.ts +62 -0
- package/src/training/operator-artifacts.js +140 -0
- package/src/training/operator-command.d.ts +5 -0
- package/src/training/operator-command.js +455 -0
- package/src/training/operator-eval.d.ts +48 -0
- package/src/training/operator-eval.js +230 -0
- package/src/training/operator-scoreboard.d.ts +5 -0
- package/src/training/operator-scoreboard.js +44 -0
- package/src/training/optimizer.js +19 -7
- package/src/training/runner.d.ts +52 -0
- package/src/training/runner.js +31 -5
- package/src/training/suite.d.ts +112 -0
- package/src/training/suite.js +24 -984
- package/src/training/tensor-factory.d.ts +9 -0
- package/src/training/tensor-factory.js +13 -0
- package/src/training/trainer.js +3 -5
- package/src/training/ul_dataset.js +3 -5
- package/src/training/workloads.d.ts +164 -0
- package/src/training/workloads.js +530 -0
- package/src/version.js +1 -1
- package/tools/convert-safetensors-node.js +22 -16
- package/tools/doppler-cli.js +179 -63
|
@@ -9,7 +9,10 @@ import {
|
|
|
9
9
|
ensureCommandSupportedOnSurface,
|
|
10
10
|
normalizeToolingCommandRequest,
|
|
11
11
|
} from './command-api.js';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isToolingSuccessEnvelope,
|
|
14
|
+
normalizeToToolingCommandError,
|
|
15
|
+
} from './command-envelope.js';
|
|
13
16
|
|
|
14
17
|
const DEFAULT_HOST = '127.0.0.1';
|
|
15
18
|
const DEFAULT_RUNNER_PATH = '/src/tooling/command-runner.html';
|
|
@@ -67,8 +70,61 @@ function resolveStaticPath(rootDir, requestPath) {
|
|
|
67
70
|
return candidate;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
function normalizeStaticMounts(mounts = []) {
|
|
74
|
+
if (!Array.isArray(mounts)) {
|
|
75
|
+
throw new Error('browser command: staticMounts must be an array.');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return mounts.map((mount, index) => {
|
|
79
|
+
if (!mount || typeof mount !== 'object' || Array.isArray(mount)) {
|
|
80
|
+
throw new Error(`browser command: staticMounts[${index}] must be an object.`);
|
|
81
|
+
}
|
|
82
|
+
const urlPrefix = String(mount.urlPrefix || '').trim();
|
|
83
|
+
const rootDir = String(mount.rootDir || '').trim();
|
|
84
|
+
if (!urlPrefix.startsWith('/')) {
|
|
85
|
+
throw new Error(`browser command: staticMounts[${index}].urlPrefix must start with "/".`);
|
|
86
|
+
}
|
|
87
|
+
if (!rootDir) {
|
|
88
|
+
throw new Error(`browser command: staticMounts[${index}].rootDir is required.`);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
urlPrefix: urlPrefix.replace(/\/+$/u, '') || '/',
|
|
92
|
+
rootDir: path.resolve(rootDir),
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function findStaticRootForRequest(rootDir, mounts, requestPath) {
|
|
98
|
+
const normalizedPath = String(requestPath || '/');
|
|
99
|
+
let bestMount = null;
|
|
100
|
+
|
|
101
|
+
for (const mount of mounts) {
|
|
102
|
+
const prefix = mount.urlPrefix;
|
|
103
|
+
if (normalizedPath !== prefix && !normalizedPath.startsWith(`${prefix}/`)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (!bestMount || prefix.length > bestMount.urlPrefix.length) {
|
|
107
|
+
bestMount = mount;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!bestMount) {
|
|
112
|
+
return {
|
|
113
|
+
effectiveRootDir: rootDir,
|
|
114
|
+
effectivePath: normalizedPath,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const relativePath = normalizedPath.slice(bestMount.urlPrefix.length) || '/';
|
|
119
|
+
return {
|
|
120
|
+
effectiveRootDir: bestMount.rootDir,
|
|
121
|
+
effectivePath: relativePath.startsWith('/') ? relativePath : `/${relativePath}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function resolveFileForRequest(rootDir, mounts, requestPath) {
|
|
126
|
+
const { effectiveRootDir, effectivePath } = findStaticRootForRequest(rootDir, mounts, requestPath);
|
|
127
|
+
const resolved = resolveStaticPath(effectiveRootDir, effectivePath);
|
|
72
128
|
if (!resolved) return null;
|
|
73
129
|
|
|
74
130
|
let stats;
|
|
@@ -99,6 +155,7 @@ async function createStaticFileServer(options = {}) {
|
|
|
99
155
|
const rootDir = path.resolve(
|
|
100
156
|
options.rootDir || fileURLToPath(new URL('../../', import.meta.url))
|
|
101
157
|
);
|
|
158
|
+
const staticMounts = normalizeStaticMounts(options.staticMounts || []);
|
|
102
159
|
const host = String(options.host || DEFAULT_HOST);
|
|
103
160
|
const port = Number.isFinite(options.port) ? Math.max(0, Math.floor(options.port)) : 0;
|
|
104
161
|
|
|
@@ -120,7 +177,7 @@ async function createStaticFileServer(options = {}) {
|
|
|
120
177
|
return;
|
|
121
178
|
}
|
|
122
179
|
|
|
123
|
-
const resolved = await resolveFileForRequest(rootDir, pathname);
|
|
180
|
+
const resolved = await resolveFileForRequest(rootDir, staticMounts, pathname);
|
|
124
181
|
if (!resolved) {
|
|
125
182
|
res.statusCode = 404;
|
|
126
183
|
res.end('File not found');
|
|
@@ -305,6 +362,26 @@ function asNonEmptyString(value) {
|
|
|
305
362
|
return normalized === '' ? null : normalized;
|
|
306
363
|
}
|
|
307
364
|
|
|
365
|
+
function createPersistentContextRequiredError(requestedLoadMode, cause = null) {
|
|
366
|
+
const baseMessage = requestedLoadMode === 'opfs'
|
|
367
|
+
? 'browser command: loadMode=opfs requires persistent browser context; persistent launch failed.'
|
|
368
|
+
: 'browser command: persistent browser context is required when OPFS cache is enabled; persistent launch failed.';
|
|
369
|
+
const causeMessage = asNonEmptyString(cause?.message || cause);
|
|
370
|
+
return new Error(
|
|
371
|
+
`${baseMessage} Re-run with run.browser.opfsCache=false to use a non-persistent browser session.${causeMessage ? ` (${causeMessage})` : ''}`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function finalizeBrowserRelayResponse(response, request) {
|
|
376
|
+
if (!isToolingSuccessEnvelope(response)) {
|
|
377
|
+
throw new Error('browser command: runner returned an invalid success envelope.');
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
...response,
|
|
381
|
+
request,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
308
385
|
function normalizeWebgpuBackend(value) {
|
|
309
386
|
const raw = asNonEmptyString(value);
|
|
310
387
|
if (!raw) return null;
|
|
@@ -516,8 +593,10 @@ async function launchPersistentBrowser(chromium, userDataDir, launchOptions, opt
|
|
|
516
593
|
|
|
517
594
|
export async function runBrowserCommandInNode(commandRequest, options = {}) {
|
|
518
595
|
let request = null;
|
|
596
|
+
let sourceRequest = null;
|
|
519
597
|
try {
|
|
520
598
|
({ request } = ensureCommandSupportedOnSurface(commandRequest, 'browser'));
|
|
599
|
+
sourceRequest = request;
|
|
521
600
|
|
|
522
601
|
if (request.keepPipeline) {
|
|
523
602
|
throw new Error(
|
|
@@ -529,320 +608,186 @@ export async function runBrowserCommandInNode(commandRequest, options = {}) {
|
|
|
529
608
|
throw new Error('browser command relay does not support convert. Use --surface node for convert commands.');
|
|
530
609
|
}
|
|
531
610
|
|
|
532
|
-
|
|
533
|
-
|
|
611
|
+
let useOpfsCache = options.opfsCache !== false;
|
|
612
|
+
let relayRequest = request;
|
|
613
|
+
const userDataDir = options.userDataDir || DEFAULT_OPFS_CACHE_DIR;
|
|
534
614
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
615
|
+
if (options.wipeCacheBeforeLaunch && useOpfsCache) {
|
|
616
|
+
await fs.rm(userDataDir, { recursive: true, force: true }).catch(() => {});
|
|
617
|
+
}
|
|
538
618
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
619
|
+
const { chromium } = await import('playwright');
|
|
620
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
621
|
+
// When OPFS caching is enabled, use a fixed port so the browser origin stays the same
|
|
622
|
+
// across runs (OPFS is origin-scoped). Without this, random ports create new origins.
|
|
623
|
+
const serverPort = options.port ?? (useOpfsCache ? DEFAULT_OPFS_CACHE_PORT : 0);
|
|
624
|
+
const server = baseUrl
|
|
625
|
+
? null
|
|
626
|
+
: await createStaticFileServer({
|
|
627
|
+
rootDir: options.staticRootDir,
|
|
628
|
+
staticMounts: options.staticMounts,
|
|
629
|
+
host: options.host,
|
|
630
|
+
port: serverPort,
|
|
631
|
+
}).catch((error) => {
|
|
632
|
+
const message = error?.message || String(error);
|
|
633
|
+
throw new Error(
|
|
634
|
+
`browser command: failed to start static server (${message}). Pass --browser-base-url to reuse an existing server.`
|
|
635
|
+
);
|
|
636
|
+
});
|
|
556
637
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
638
|
+
const launchOptions = {
|
|
639
|
+
headless: normalizeHeadless(options.headless),
|
|
640
|
+
args: browserLaunchArgs(normalizeBrowserArgs(options.browserArgs)),
|
|
641
|
+
};
|
|
561
642
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
643
|
+
if (options.channel) {
|
|
644
|
+
launchOptions.channel = String(options.channel);
|
|
645
|
+
}
|
|
646
|
+
if (options.executablePath) {
|
|
647
|
+
launchOptions.executablePath = String(options.executablePath);
|
|
648
|
+
}
|
|
568
649
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
}
|
|
650
|
+
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
651
|
+
const runnerPath = normalizeRunnerPath(options.runnerPath);
|
|
652
|
+
const resolvedBaseUrl = baseUrl || server.baseUrl;
|
|
653
|
+
const requestedLoadMode = sourceRequest.loadMode;
|
|
654
|
+
const requireOpfsLoad = requestedLoadMode === 'opfs';
|
|
655
|
+
if (requireOpfsLoad && useOpfsCache === false) {
|
|
656
|
+
throw new Error('browser command: loadMode=opfs requires OPFS cache support (remove --no-opfs-cache).');
|
|
657
|
+
}
|
|
658
|
+
if (requireOpfsLoad && sourceRequest.modelUrl && !sourceRequest.modelId) {
|
|
659
|
+
throw new Error(
|
|
660
|
+
'browser command: loadMode=opfs requires modelId when modelUrl is provided so the relay can verify and load the cached OPFS artifact.'
|
|
661
|
+
);
|
|
662
|
+
}
|
|
583
663
|
|
|
584
664
|
let browser = null;
|
|
585
665
|
let context = null;
|
|
586
666
|
try {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
try {
|
|
591
|
-
context = await launchPersistentBrowser(chromium, userDataDir, launchOptions, {
|
|
592
|
-
explicitChannel: Boolean(options.channel),
|
|
593
|
-
explicitExecutablePath: Boolean(options.executablePath),
|
|
594
|
-
});
|
|
595
|
-
} catch (error) {
|
|
596
|
-
if (!isRecoverablePersistentLaunchError(error)) {
|
|
597
|
-
throw error;
|
|
598
|
-
}
|
|
599
|
-
if (typeof options.onConsole === 'function') {
|
|
600
|
-
options.onConsole({
|
|
601
|
-
type: 'warning',
|
|
602
|
-
text: '[browser] Persistent browser launch failed; retrying with a clean OPFS profile.',
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
await fs.rm(userDataDir, { recursive: true, force: true }).catch(() => {});
|
|
667
|
+
if (useOpfsCache) {
|
|
668
|
+
// Persistent context: OPFS data survives between runs.
|
|
669
|
+
// launchPersistentContext returns a BrowserContext directly (no separate Browser).
|
|
606
670
|
try {
|
|
607
671
|
context = await launchPersistentBrowser(chromium, userDataDir, launchOptions, {
|
|
608
672
|
explicitChannel: Boolean(options.channel),
|
|
609
673
|
explicitExecutablePath: Boolean(options.executablePath),
|
|
610
674
|
});
|
|
611
|
-
} catch (
|
|
612
|
-
if (!isRecoverablePersistentLaunchError(
|
|
613
|
-
throw
|
|
675
|
+
} catch (error) {
|
|
676
|
+
if (!isRecoverablePersistentLaunchError(error)) {
|
|
677
|
+
throw error;
|
|
614
678
|
}
|
|
615
679
|
if (typeof options.onConsole === 'function') {
|
|
616
680
|
options.onConsole({
|
|
617
681
|
type: 'warning',
|
|
618
|
-
text: '[browser] Persistent launch
|
|
682
|
+
text: '[browser] Persistent browser launch failed; retrying with a clean OPFS profile.',
|
|
619
683
|
});
|
|
620
684
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
685
|
+
await fs.rm(userDataDir, { recursive: true, force: true }).catch(() => {});
|
|
686
|
+
try {
|
|
687
|
+
context = await launchPersistentBrowser(chromium, userDataDir, launchOptions, {
|
|
688
|
+
explicitChannel: Boolean(options.channel),
|
|
689
|
+
explicitExecutablePath: Boolean(options.executablePath),
|
|
690
|
+
});
|
|
691
|
+
} catch (retryError) {
|
|
692
|
+
if (!isRecoverablePersistentLaunchError(retryError)) {
|
|
693
|
+
throw retryError;
|
|
694
|
+
}
|
|
695
|
+
throw createPersistentContextRequiredError(requestedLoadMode, retryError);
|
|
632
696
|
}
|
|
633
|
-
browser = await launchBrowser(chromium, launchOptions, {
|
|
634
|
-
explicitChannel: Boolean(options.channel),
|
|
635
|
-
explicitExecutablePath: Boolean(options.executablePath),
|
|
636
|
-
});
|
|
637
|
-
context = await browser.newContext();
|
|
638
697
|
}
|
|
698
|
+
} else {
|
|
699
|
+
browser = await launchBrowser(chromium, launchOptions, {
|
|
700
|
+
explicitChannel: Boolean(options.channel),
|
|
701
|
+
explicitExecutablePath: Boolean(options.executablePath),
|
|
702
|
+
});
|
|
703
|
+
context = await browser.newContext();
|
|
639
704
|
}
|
|
640
|
-
} else {
|
|
641
|
-
browser = await launchBrowser(chromium, launchOptions, {
|
|
642
|
-
explicitChannel: Boolean(options.channel),
|
|
643
|
-
explicitExecutablePath: Boolean(options.executablePath),
|
|
644
|
-
});
|
|
645
|
-
context = await browser.newContext();
|
|
646
|
-
}
|
|
647
705
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
706
|
+
const page = await context.newPage();
|
|
707
|
+
page.setDefaultTimeout(timeoutMs);
|
|
708
|
+
const pageDiagnostics = [];
|
|
651
709
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
710
|
+
if (typeof options.onConsole === 'function') {
|
|
711
|
+
page.on('console', (message) => {
|
|
712
|
+
options.onConsole({
|
|
713
|
+
type: message.type(),
|
|
714
|
+
text: message.text(),
|
|
715
|
+
});
|
|
657
716
|
});
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
page.on('pageerror', (error) => {
|
|
662
|
-
pageDiagnostics.push(`pageerror: ${error?.message || String(error)}`);
|
|
663
|
-
});
|
|
664
|
-
page.on('requestfailed', (request) => {
|
|
665
|
-
const failure = request.failure();
|
|
666
|
-
pageDiagnostics.push(
|
|
667
|
-
`requestfailed: ${request.url()} (${failure?.errorText || 'unknown error'})`
|
|
668
|
-
);
|
|
669
|
-
});
|
|
717
|
+
}
|
|
670
718
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
719
|
+
page.on('pageerror', (error) => {
|
|
720
|
+
pageDiagnostics.push(`pageerror: ${error?.message || String(error)}`);
|
|
721
|
+
});
|
|
722
|
+
page.on('requestfailed', (request) => {
|
|
723
|
+
const failure = request.failure();
|
|
724
|
+
pageDiagnostics.push(
|
|
725
|
+
`requestfailed: ${request.url()} (${failure?.errorText || 'unknown error'})`
|
|
726
|
+
);
|
|
677
727
|
});
|
|
678
|
-
} catch (error) {
|
|
679
|
-
const diagnostics = pageDiagnostics.length
|
|
680
|
-
? pageDiagnostics.slice(0, 10).join(' | ')
|
|
681
|
-
: 'no page diagnostics captured';
|
|
682
|
-
throw new Error(
|
|
683
|
-
`browser command: runner did not become ready within ${timeoutMs}ms (${diagnostics}).`
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
728
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
729
|
+
const runnerUrl = new URL(runnerPath, resolvedBaseUrl);
|
|
730
|
+
runnerUrl.searchParams.set('_dopplerRunner', String(Date.now()));
|
|
731
|
+
await page.goto(runnerUrl.toString(), { waitUntil: 'load' });
|
|
690
732
|
try {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
return { cached: false, error: '__dopplerEnsureCached not available' };
|
|
694
|
-
}
|
|
695
|
-
return globalThis.__dopplerEnsureCached(payload.modelId, payload.modelBaseUrl);
|
|
696
|
-
}, {
|
|
697
|
-
modelId: request.modelId,
|
|
698
|
-
modelBaseUrl: request.modelUrl,
|
|
733
|
+
await page.waitForFunction(() => globalThis.__dopplerRunnerReady === true, null, {
|
|
734
|
+
timeout: timeoutMs,
|
|
699
735
|
});
|
|
736
|
+
} catch (error) {
|
|
737
|
+
const diagnostics = pageDiagnostics.length
|
|
738
|
+
? pageDiagnostics.slice(0, 10).join(' | ')
|
|
739
|
+
: 'no page diagnostics captured';
|
|
740
|
+
throw new Error(
|
|
741
|
+
`browser command: runner did not become ready within ${timeoutMs}ms (${diagnostics}).`
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Explicit loadMode=opfs must be satisfied without rewriting the shared request contract.
|
|
746
|
+
if (useOpfsCache && requireOpfsLoad && relayRequest.modelId && relayRequest.modelUrl) {
|
|
747
|
+
try {
|
|
748
|
+
const cacheResult = await page.evaluate(async (payload) => {
|
|
749
|
+
if (typeof globalThis.__dopplerEnsureCached !== 'function') {
|
|
750
|
+
return { cached: false, error: '__dopplerEnsureCached not available' };
|
|
751
|
+
}
|
|
752
|
+
return globalThis.__dopplerEnsureCached(payload.modelId, payload.modelBaseUrl);
|
|
753
|
+
}, {
|
|
754
|
+
modelId: relayRequest.modelId,
|
|
755
|
+
modelBaseUrl: relayRequest.modelUrl,
|
|
756
|
+
});
|
|
700
757
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
request.loadMode = 'opfs';
|
|
706
|
-
} else {
|
|
707
|
-
if (requireOpfsLoad) {
|
|
758
|
+
if (cacheResult.cached) {
|
|
759
|
+
relayRequest = { ...relayRequest };
|
|
760
|
+
delete relayRequest.modelUrl;
|
|
761
|
+
} else {
|
|
708
762
|
const cacheError = cacheResult?.error || 'model not cached';
|
|
709
763
|
throw new Error(
|
|
710
|
-
`[opfs-cache]
|
|
764
|
+
`[opfs-cache] model cache is unavailable for "${relayRequest.modelId || 'unknown-model'}": ${cacheError}.`
|
|
711
765
|
);
|
|
712
766
|
}
|
|
713
|
-
|
|
714
|
-
request = { ...request, loadMode: 'http' };
|
|
715
|
-
}
|
|
716
|
-
if (cacheResult.error) {
|
|
717
|
-
if (typeof options.onConsole === 'function') {
|
|
718
|
-
options.onConsole({
|
|
719
|
-
type: 'warning',
|
|
720
|
-
text: `[opfs-cache] Cache check failed (${cacheResult.error}), falling back to HTTP`,
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
} catch (error) {
|
|
726
|
-
if (requireOpfsLoad) {
|
|
767
|
+
} catch (error) {
|
|
727
768
|
throw new Error(
|
|
728
|
-
`[opfs-cache]
|
|
769
|
+
`[opfs-cache] cache priming failed: ${error?.message || error}.`
|
|
729
770
|
);
|
|
730
771
|
}
|
|
731
|
-
if (!requestedLoadMode && request.modelUrl) {
|
|
732
|
-
request = { ...request, loadMode: 'http' };
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// OPFS cache is best-effort; fall back to HTTP on any error.
|
|
736
|
-
if (typeof options.onConsole === 'function') {
|
|
737
|
-
options.onConsole({
|
|
738
|
-
type: 'warning',
|
|
739
|
-
text: `[opfs-cache] Error (${error?.message || error}), falling back to HTTP`,
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
const response = await page.evaluate(async (payload) => {
|
|
746
|
-
if (typeof globalThis.__dopplerRunBrowserCommand !== 'function') {
|
|
747
|
-
throw new Error('browser command runner is missing globalThis.__dopplerRunBrowserCommand');
|
|
748
772
|
}
|
|
749
|
-
return globalThis.__dopplerRunBrowserCommand(payload.request, payload.options || {});
|
|
750
|
-
}, {
|
|
751
|
-
request,
|
|
752
|
-
options: {
|
|
753
|
-
runtimeLoadOptions: options.runtimeLoadOptions || {},
|
|
754
|
-
},
|
|
755
|
-
});
|
|
756
773
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
};
|
|
767
|
-
const webgpuBackend = inferWebgpuBackendFromArgs(launchOptions.args, hostEnvironment.platform);
|
|
768
|
-
const env = result.env && typeof result.env === 'object' ? result.env : {};
|
|
769
|
-
const deviceInfo = result.deviceInfo && typeof result.deviceInfo === 'object'
|
|
770
|
-
? result.deviceInfo
|
|
771
|
-
: {};
|
|
772
|
-
result.env = {
|
|
773
|
-
...env,
|
|
774
|
-
webgpuBackend: normalizeWebgpuBackend(env.webgpuBackend)
|
|
775
|
-
|| normalizeWebgpuBackend(env.gpuBackend)
|
|
776
|
-
|| normalizeWebgpuBackend(env.graphicsBackend)
|
|
777
|
-
|| webgpuBackend,
|
|
778
|
-
};
|
|
779
|
-
const existingEnvironment = result.environment && typeof result.environment === 'object'
|
|
780
|
-
? result.environment
|
|
781
|
-
: {};
|
|
782
|
-
result.environment = {
|
|
783
|
-
...existingEnvironment,
|
|
784
|
-
host: {
|
|
785
|
-
...(existingEnvironment.host && typeof existingEnvironment.host === 'object' ? existingEnvironment.host : {}),
|
|
786
|
-
platform: asNonEmptyString(existingEnvironment?.host?.platform) || hostEnvironment.platform,
|
|
787
|
-
arch: asNonEmptyString(existingEnvironment?.host?.arch) || hostEnvironment.arch,
|
|
788
|
-
nodeVersion: asNonEmptyString(existingEnvironment?.host?.nodeVersion) || hostEnvironment.nodeVersion,
|
|
789
|
-
osRelease: asNonEmptyString(existingEnvironment?.host?.osRelease) || hostEnvironment.osRelease,
|
|
790
|
-
cpuModel: asNonEmptyString(existingEnvironment?.host?.cpuModel) || hostEnvironment.cpuModel,
|
|
791
|
-
},
|
|
792
|
-
browser: {
|
|
793
|
-
...(existingEnvironment.browser && typeof existingEnvironment.browser === 'object' ? existingEnvironment.browser : {}),
|
|
794
|
-
userAgent: asNonEmptyString(existingEnvironment?.browser?.userAgent) || asNonEmptyString(env.browserUserAgent),
|
|
795
|
-
platform: asNonEmptyString(existingEnvironment?.browser?.platform) || asNonEmptyString(env.browserPlatform),
|
|
796
|
-
language: asNonEmptyString(existingEnvironment?.browser?.language) || asNonEmptyString(env.browserLanguage),
|
|
797
|
-
vendor: asNonEmptyString(existingEnvironment?.browser?.vendor) || asNonEmptyString(env.browserVendor),
|
|
798
|
-
executable: asNonEmptyString(existingEnvironment?.browser?.executable) || asNonEmptyString(options.executablePath),
|
|
799
|
-
channel: asNonEmptyString(existingEnvironment?.browser?.channel) || asNonEmptyString(options.channel),
|
|
800
|
-
},
|
|
801
|
-
gpu: {
|
|
802
|
-
...(existingEnvironment.gpu && typeof existingEnvironment.gpu === 'object' ? existingEnvironment.gpu : {}),
|
|
803
|
-
api: asNonEmptyString(existingEnvironment?.gpu?.api) || 'webgpu',
|
|
804
|
-
backend: normalizeWebgpuBackend(existingEnvironment?.gpu?.backend)
|
|
805
|
-
|| normalizeWebgpuBackend(env.webgpuBackend)
|
|
806
|
-
|| webgpuBackend,
|
|
807
|
-
vendor: asNonEmptyString(existingEnvironment?.gpu?.vendor) || asNonEmptyString(deviceInfo.vendor),
|
|
808
|
-
architecture: asNonEmptyString(existingEnvironment?.gpu?.architecture) || asNonEmptyString(deviceInfo.architecture),
|
|
809
|
-
device: asNonEmptyString(existingEnvironment?.gpu?.device) || asNonEmptyString(deviceInfo.device),
|
|
810
|
-
description: asNonEmptyString(existingEnvironment?.gpu?.description) || asNonEmptyString(deviceInfo.description),
|
|
811
|
-
hasF16: typeof existingEnvironment?.gpu?.hasF16 === 'boolean'
|
|
812
|
-
? existingEnvironment.gpu.hasF16
|
|
813
|
-
: (typeof deviceInfo.hasF16 === 'boolean' ? deviceInfo.hasF16 : null),
|
|
814
|
-
hasSubgroups: typeof existingEnvironment?.gpu?.hasSubgroups === 'boolean'
|
|
815
|
-
? existingEnvironment.gpu.hasSubgroups
|
|
816
|
-
: (typeof deviceInfo.hasSubgroups === 'boolean' ? deviceInfo.hasSubgroups : null),
|
|
817
|
-
hasTimestampQuery: typeof existingEnvironment?.gpu?.hasTimestampQuery === 'boolean'
|
|
818
|
-
? existingEnvironment.gpu.hasTimestampQuery
|
|
819
|
-
: (typeof deviceInfo.hasTimestampQuery === 'boolean' ? deviceInfo.hasTimestampQuery : null),
|
|
820
|
-
},
|
|
821
|
-
runtime: {
|
|
822
|
-
...(existingEnvironment.runtime && typeof existingEnvironment.runtime === 'object' ? existingEnvironment.runtime : {}),
|
|
823
|
-
library: asNonEmptyString(existingEnvironment?.runtime?.library) || asNonEmptyString(env.library) || 'doppler',
|
|
824
|
-
version: asNonEmptyString(existingEnvironment?.runtime?.version) || asNonEmptyString(env.version),
|
|
825
|
-
surface: asNonEmptyString(existingEnvironment?.runtime?.surface) || asNonEmptyString(env.runtime) || 'browser',
|
|
826
|
-
device: asNonEmptyString(existingEnvironment?.runtime?.device) || asNonEmptyString(env.device),
|
|
827
|
-
dtype: asNonEmptyString(existingEnvironment?.runtime?.dtype) || asNonEmptyString(env.dtype),
|
|
828
|
-
requestedDtype: asNonEmptyString(existingEnvironment?.runtime?.requestedDtype) || asNonEmptyString(env.requestedDtype),
|
|
829
|
-
executionProviderMode: asNonEmptyString(existingEnvironment?.runtime?.executionProviderMode)
|
|
830
|
-
|| asNonEmptyString(env.executionProviderMode),
|
|
831
|
-
cacheMode: asNonEmptyString(existingEnvironment?.runtime?.cacheMode)
|
|
832
|
-
|| asNonEmptyString(result.cacheMode)
|
|
833
|
-
|| asNonEmptyString(result?.timing?.cacheMode),
|
|
834
|
-
loadMode: asNonEmptyString(existingEnvironment?.runtime?.loadMode)
|
|
835
|
-
|| asNonEmptyString(result.loadMode)
|
|
836
|
-
|| asNonEmptyString(result?.timing?.loadMode),
|
|
774
|
+
const response = await page.evaluate(async (payload) => {
|
|
775
|
+
if (typeof globalThis.__dopplerRunBrowserCommand !== 'function') {
|
|
776
|
+
throw new Error('browser command runner is missing globalThis.__dopplerRunBrowserCommand');
|
|
777
|
+
}
|
|
778
|
+
return globalThis.__dopplerRunBrowserCommand(payload.request, payload.options || {});
|
|
779
|
+
}, {
|
|
780
|
+
request: relayRequest,
|
|
781
|
+
options: {
|
|
782
|
+
runtimeLoadOptions: options.runtimeLoadOptions || {},
|
|
837
783
|
},
|
|
838
|
-
};
|
|
839
|
-
}
|
|
784
|
+
});
|
|
840
785
|
|
|
841
|
-
return response;
|
|
786
|
+
return finalizeBrowserRelayResponse(response, sourceRequest);
|
|
842
787
|
} catch (error) {
|
|
843
788
|
throw normalizeToToolingCommandError(error, {
|
|
844
789
|
surface: 'browser',
|
|
845
|
-
request,
|
|
790
|
+
request: sourceRequest,
|
|
846
791
|
});
|
|
847
792
|
} finally {
|
|
848
793
|
if (context) {
|
|
@@ -858,7 +803,7 @@ export async function runBrowserCommandInNode(commandRequest, options = {}) {
|
|
|
858
803
|
} catch (error) {
|
|
859
804
|
throw normalizeToToolingCommandError(error, {
|
|
860
805
|
surface: 'browser',
|
|
861
|
-
request,
|
|
806
|
+
request: sourceRequest,
|
|
862
807
|
});
|
|
863
808
|
}
|
|
864
809
|
}
|