rechrome 1.35.1 → 1.36.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/README.md +79 -0
- package/extension/lib/background.mjs +28 -1
- package/extension/lib/ui/connect.js +29 -19
- package/listeners.js +17 -1
- package/listeners.ts +7 -2
- package/package.json +5 -3
- package/rechrome.js +101 -17
- package/rechrome.ts +101 -17
- package/scoped-upload.js +165 -0
- package/scoped-upload.ts +140 -0
- package/serve.js +140 -25
- package/serve.ts +140 -25
- package/vendor/playwright-cli/node_modules/playwright-core/lib/coreBundle.js +360 -256
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-client/help.json +9 -4
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-client/program.js +6 -1
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-client/session.js +10 -12
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/utils/extension.js +8 -5
- package/vendor/playwright-cli/node_modules/playwright-core/lib/androidServerImpl.js +0 -65
- package/vendor/playwright-cli/node_modules/playwright-core/lib/browserServerImpl.js +0 -120
- package/vendor/playwright-cli/node_modules/playwright-core/lib/cli/driver.js +0 -98
- package/vendor/playwright-cli/node_modules/playwright-core/lib/cli/program.js +0 -597
- package/vendor/playwright-cli/node_modules/playwright-core/lib/cli/programWithTestStub.js +0 -74
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/android.js +0 -361
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/api.js +0 -137
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/artifact.js +0 -79
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/browser.js +0 -169
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/browserContext.js +0 -583
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/browserType.js +0 -153
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/cdpSession.js +0 -55
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/channelOwner.js +0 -194
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/clientHelper.js +0 -64
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/clientInstrumentation.js +0 -55
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/clientStackTrace.js +0 -69
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/clock.js +0 -68
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/connect.js +0 -143
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/connection.js +0 -322
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/consoleMessage.js +0 -61
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/coverage.js +0 -44
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/debugger.js +0 -57
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/dialog.js +0 -56
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/disposable.js +0 -76
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/download.js +0 -62
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/electron.js +0 -138
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/elementHandle.js +0 -281
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/errors.js +0 -77
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/eventEmitter.js +0 -314
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/events.js +0 -103
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/fetch.js +0 -367
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/fileChooser.js +0 -46
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/fileUtils.js +0 -34
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/frame.js +0 -404
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/harRouter.js +0 -99
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/input.js +0 -84
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/jsHandle.js +0 -105
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/jsonPipe.js +0 -39
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/localUtils.js +0 -60
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/locator.js +0 -367
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/network.js +0 -750
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/page.js +0 -729
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/platform.js +0 -77
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/playwright.js +0 -71
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/screencast.js +0 -48
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/selectors.js +0 -57
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/stream.js +0 -39
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/timeoutSettings.js +0 -79
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/tracing.js +0 -126
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/types.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/video.js +0 -68
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/waiter.js +0 -142
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/webError.js +0 -39
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/worker.js +0 -85
- package/vendor/playwright-cli/node_modules/playwright-core/lib/client/writableStream.js +0 -39
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/bindingsControllerSource.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/clockSource.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/injectedScriptSource.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/pollingRecorderSource.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/storageScriptSource.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/utilityScriptSource.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/generated/webSocketMockSource.js +0 -336
- package/vendor/playwright-cli/node_modules/playwright-core/lib/inProcessFactory.js +0 -60
- package/vendor/playwright-cli/node_modules/playwright-core/lib/inprocess.js +0 -3
- package/vendor/playwright-cli/node_modules/playwright-core/lib/mcpBundle.js +0 -81
- package/vendor/playwright-cli/node_modules/playwright-core/lib/mcpBundleImpl/index.js +0 -91
- package/vendor/playwright-cli/node_modules/playwright-core/lib/outofprocess.js +0 -76
- package/vendor/playwright-cli/node_modules/playwright-core/lib/protocol/serializers.js +0 -197
- package/vendor/playwright-cli/node_modules/playwright-core/lib/protocol/validator.js +0 -3034
- package/vendor/playwright-cli/node_modules/playwright-core/lib/protocol/validatorPrimitives.js +0 -193
- package/vendor/playwright-cli/node_modules/playwright-core/lib/remote/playwrightConnection.js +0 -131
- package/vendor/playwright-cli/node_modules/playwright-core/lib/remote/playwrightPipeServer.js +0 -100
- package/vendor/playwright-cli/node_modules/playwright-core/lib/remote/playwrightServer.js +0 -339
- package/vendor/playwright-cli/node_modules/playwright-core/lib/remote/playwrightWebSocketServer.js +0 -73
- package/vendor/playwright-cli/node_modules/playwright-core/lib/remote/serverTransport.js +0 -96
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/android/android.js +0 -465
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/android/backendAdb.js +0 -177
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/artifact.js +0 -127
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiBrowser.js +0 -571
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiChromium.js +0 -162
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiConnection.js +0 -213
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiDeserializer.js +0 -116
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiExecutionContext.js +0 -267
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiFirefox.js +0 -128
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiInput.js +0 -146
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiNetworkManager.js +0 -411
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiOverCdp.js +0 -102
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiPage.js +0 -599
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/bidiPdf.js +0 -106
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/bidiCommands.d.js +0 -22
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/bidiKeyboard.js +0 -256
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/bidiProtocol.js +0 -24
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/bidiProtocolCore.js +0 -180
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/bidiProtocolPermissions.js +0 -42
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/bidiSerializer.js +0 -148
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/bidi/third_party/firefoxPrefs.js +0 -261
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/browser.js +0 -223
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/browserContext.js +0 -703
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/browserType.js +0 -338
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/callLog.js +0 -82
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/chromium.js +0 -399
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/chromiumSwitches.js +0 -104
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crBrowser.js +0 -532
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crConnection.js +0 -197
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crCoverage.js +0 -235
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crDevTools.js +0 -111
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crDragDrop.js +0 -131
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crExecutionContext.js +0 -146
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crInput.js +0 -187
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crNetworkManager.js +0 -708
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crPage.js +0 -1004
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crPdf.js +0 -121
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crProtocolHelper.js +0 -145
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/crServiceWorker.js +0 -137
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/defaultFontFamilies.js +0 -162
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/chromium/protocol.d.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/clock.js +0 -149
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/csharp.js +0 -327
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/java.js +0 -274
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/javascript.js +0 -247
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/jsonl.js +0 -52
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/language.js +0 -132
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/languages.js +0 -68
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/python.js +0 -279
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/codegen/types.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/console.js +0 -61
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/cookieStore.js +0 -206
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/debugController.js +0 -197
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/debugger.js +0 -120
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/deviceDescriptors.js +0 -39
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dialog.js +0 -116
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/androidDispatcher.js +0 -325
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/artifactDispatcher.js +0 -118
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/browserContextDispatcher.js +0 -381
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/browserDispatcher.js +0 -124
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/browserTypeDispatcher.js +0 -71
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/cdpSessionDispatcher.js +0 -47
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/debugControllerDispatcher.js +0 -78
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/debuggerDispatcher.js +0 -80
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/dialogDispatcher.js +0 -47
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/dispatcher.js +0 -364
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/disposableDispatcher.js +0 -39
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/electronDispatcher.js +0 -90
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/elementHandlerDispatcher.js +0 -181
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/frameDispatcher.js +0 -227
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/jsHandleDispatcher.js +0 -85
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/jsonPipeDispatcher.js +0 -58
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/localUtilsDispatcher.js +0 -185
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/networkDispatchers.js +0 -214
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/pageDispatcher.js +0 -434
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/playwrightDispatcher.js +0 -108
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/streamDispatcher.js +0 -67
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/tracingDispatcher.js +0 -68
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/webSocketRouteDispatcher.js +0 -164
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dispatchers/writableStreamDispatcher.js +0 -79
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/disposable.js +0 -41
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/dom.js +0 -823
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/download.js +0 -71
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/electron/electron.js +0 -272
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/electron/loader.js +0 -115
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/errors.js +0 -69
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/fetch.js +0 -621
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/fileChooser.js +0 -43
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/fileUploadUtils.js +0 -84
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/ffBrowser.js +0 -415
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/ffConnection.js +0 -142
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/ffExecutionContext.js +0 -150
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/ffInput.js +0 -175
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/ffNetworkManager.js +0 -256
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/ffPage.js +0 -495
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/firefox.js +0 -114
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/firefox/protocol.d.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/formData.js +0 -147
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/frameSelectors.js +0 -160
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/frames.js +0 -1495
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/har/harRecorder.js +0 -147
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/har/harTracer.js +0 -608
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/harBackend.js +0 -157
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/helper.js +0 -96
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/index.js +0 -58
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/input.js +0 -277
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/instrumentation.js +0 -72
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/javascript.js +0 -291
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/launchApp.js +0 -127
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/localUtils.js +0 -214
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/macEditingCommands.js +0 -143
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/network.js +0 -668
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/page.js +0 -884
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/pipeTransport.js +0 -89
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/playwright.js +0 -69
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/progress.js +0 -136
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/protocolError.js +0 -52
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder/chat.js +0 -161
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder/recorderApp.js +0 -367
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder/recorderRunner.js +0 -138
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +0 -83
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder/recorderUtils.js +0 -157
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder/throttledFile.js +0 -57
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/recorder.js +0 -540
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/registry/browserFetcher.js +0 -177
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/registry/dependencies.js +0 -371
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/registry/index.js +0 -1395
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/registry/nativeDeps.js +0 -1281
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/registry/oopDownloadBrowserMain.js +0 -127
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/screencast.js +0 -216
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/screenshotter.js +0 -333
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/selectors.js +0 -112
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/socksClientCertificatesInterceptor.js +0 -383
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/socksInterceptor.js +0 -95
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/trace/recorder/snapshotter.js +0 -147
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/trace/recorder/snapshotterInjected.js +0 -561
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/trace/recorder/tracing.js +0 -607
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/trace/viewer/traceViewer.js +0 -244
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/transport.js +0 -181
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/types.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/usKeyboardLayout.js +0 -152
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/ascii.js +0 -44
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/comparators.js +0 -139
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/crypto.js +0 -216
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/debug.js +0 -42
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/debugLogger.js +0 -122
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/disposable.js +0 -32
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/env.js +0 -73
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/eventsHelper.js +0 -41
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/expectUtils.js +0 -123
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/fileUtils.js +0 -191
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/happyEyeballs.js +0 -207
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/hostPlatform.js +0 -123
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/httpServer.js +0 -205
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/image_tools/colorUtils.js +0 -89
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/image_tools/compare.js +0 -109
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/image_tools/imageChannel.js +0 -78
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/image_tools/stats.js +0 -102
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/linuxUtils.js +0 -71
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/network.js +0 -244
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/nodePlatform.js +0 -154
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/pipeTransport.js +0 -84
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/processLauncher.js +0 -243
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/profiler.js +0 -65
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/socksProxy.js +0 -511
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/spawnAsync.js +0 -41
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/task.js +0 -51
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/userAgent.js +0 -98
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/wsServer.js +0 -121
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/zipFile.js +0 -74
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/utils/zones.js +0 -57
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/videoRecorder.js +0 -133
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/protocol.d.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/webkit.js +0 -108
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkBrowser.js +0 -331
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkConnection.js +0 -144
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkExecutionContext.js +0 -154
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkInput.js +0 -181
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkInterceptableRequest.js +0 -197
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkPage.js +0 -1164
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkProvisionalPage.js +0 -83
- package/vendor/playwright-cli/node_modules/playwright-core/lib/server/webkit/wkWorkers.js +0 -106
- package/vendor/playwright-cli/node_modules/playwright-core/lib/third_party/pixelmatch.js +0 -255
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/browserBackend.js +0 -79
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/common.js +0 -63
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/config.js +0 -41
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/console.js +0 -66
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/context.js +0 -290
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/cookies.js +0 -152
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/devtools.js +0 -69
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/dialogs.js +0 -59
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/evaluate.js +0 -64
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/files.js +0 -60
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/form.js +0 -64
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/keyboard.js +0 -155
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/logFile.js +0 -95
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/mouse.js +0 -168
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/navigate.js +0 -106
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/network.js +0 -135
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/pdf.js +0 -48
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/response.js +0 -302
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/route.js +0 -140
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/runCode.js +0 -76
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/screenshot.js +0 -88
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/sessionLog.js +0 -74
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/snapshot.js +0 -208
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/storage.js +0 -67
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/tab.js +0 -445
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/tabs.js +0 -67
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/tool.js +0 -47
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/tools.js +0 -102
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/tracing.js +0 -75
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/utils.js +0 -83
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/verify.js +0 -151
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/video.js +0 -89
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/wait.js +0 -63
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/backend/webstorage.js +0 -223
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-daemon/command.js +0 -73
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-daemon/commands.js +0 -933
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-daemon/daemon.js +0 -178
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-daemon/helpGenerator.js +0 -173
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/cli-daemon/program.js +0 -118
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/dashboard/dashboardApp.js +0 -286
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/dashboard/dashboardController.js +0 -296
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/exports.js +0 -60
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/browserFactory.js +0 -233
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/cdpRelay.js +0 -356
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/cli-stub.js +0 -7
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/config.d.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/config.js +0 -401
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/configIni.js +0 -189
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/extensionContextFactory.js +0 -59
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/index.js +0 -62
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/log.js +0 -35
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/program.js +0 -107
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/protocol.js +0 -28
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/mcp/watchdog.js +0 -44
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/installSkill.js +0 -48
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceActions.js +0 -142
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceAttachments.js +0 -69
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceCli.js +0 -80
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceConsole.js +0 -97
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceErrors.js +0 -55
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceOpen.js +0 -69
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceParser.js +0 -96
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceRequests.js +0 -158
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceScreenshot.js +0 -68
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceSnapshot.js +0 -149
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/trace/traceUtils.js +0 -135
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/utils/connect.js +0 -32
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/utils/mcp/http.js +0 -152
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/utils/mcp/server.js +0 -230
- package/vendor/playwright-cli/node_modules/playwright-core/lib/tools/utils/mcp/tool.js +0 -47
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/ariaSnapshot.js +0 -455
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/assert.js +0 -31
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/colors.js +0 -72
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/cssParser.js +0 -245
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/cssTokenizer.js +0 -1051
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/formatUtils.js +0 -64
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/headers.js +0 -53
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/imageUtils.js +0 -141
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/locatorGenerators.js +0 -689
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/locatorParser.js +0 -176
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/locatorUtils.js +0 -81
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/lruCache.js +0 -51
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/manualPromise.js +0 -114
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/mimeType.js +0 -464
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/multimap.js +0 -80
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/protocolFormatter.js +0 -81
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/protocolMetainfo.js +0 -342
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/rtti.js +0 -43
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/selectorParser.js +0 -386
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/semaphore.js +0 -54
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/stackTrace.js +0 -158
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/stringUtils.js +0 -204
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/time.js +0 -49
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/timeoutRunner.js +0 -66
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/entries.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/snapshotRenderer.js +0 -502
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/snapshotServer.js +0 -120
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/snapshotStorage.js +0 -89
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/traceLoader.js +0 -131
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/traceModel.js +0 -366
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/traceModernizer.js +0 -401
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/traceUtils.js +0 -58
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/versions/traceV3.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/versions/traceV4.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/versions/traceV5.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/versions/traceV6.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/versions/traceV7.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/trace/versions/traceV8.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/types.js +0 -16
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/urlMatch.js +0 -243
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/utilityScriptSerializers.js +0 -262
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils/isomorphic/yaml.js +0 -84
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utils.js +0 -113
- package/vendor/playwright-cli/node_modules/playwright-core/lib/utilsBundleImpl/index.js +0 -218
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BtGnd8kr.js +0 -32
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-CnvO0fko.js +0 -32
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-BkMbME_o.js +0 -262
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-CN3cwLGD.js +0 -262
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.B4dS75f0.css +0 -1
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.DcQiWcKS.css +0 -1
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/index.B2ffe31o.js +0 -2
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/index.Df3uWWXm.js +0 -2
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/uiMode.BZQ54Kgt.css +0 -1
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CmAqMvmy.js +0 -6
- package/vendor/playwright-cli/node_modules/playwright-core/lib/vite/traceViewer/uiMode.u9Eas4CP.js +0 -6
- package/vendor/playwright-cli/node_modules/playwright-core/lib/zipBundle.js +0 -34
- package/vendor/playwright-cli/node_modules/playwright-core/lib/zipBundleImpl.js +0 -5
package/rechrome.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { prepareStdinUpload, type UploadPayload } from "./scoped-upload.ts";
|
|
2
3
|
import { readListeners, writeListeners, listenerAddress, isLoopback, normalizePrefix, serviceUrl, allowProfiles, denyProfiles, rotateListenerKey, setPublicUrl, canonicalProfileKeys, planProfileRemoval, type Listener } from "./listeners.ts";
|
|
3
4
|
|
|
4
5
|
import { file } from "bun";
|
|
@@ -827,18 +828,53 @@ const CHROME_LOCAL_STATE_PATHS = () => {
|
|
|
827
828
|
|
|
828
829
|
type ChromeProfileInfo = { user_name?: string; name?: string };
|
|
829
830
|
|
|
831
|
+
/**
|
|
832
|
+
* macOS privacy (TCC) blocks a process launched by launchd/oxmgr from Chrome's data folder unless
|
|
833
|
+
* its binary has Full Disk Access; a Terminal or agent session inherits the grant. Turn that EPERM
|
|
834
|
+
* into the fix. Undefined for any other error (or platform).
|
|
835
|
+
*/
|
|
836
|
+
export function chromeDataAccessHint(error: unknown, execPath = process.execPath, platform = process.platform): string | undefined {
|
|
837
|
+
const code = (error as { code?: string } | null)?.code;
|
|
838
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
839
|
+
if (platform !== "darwin" || !(code === "EPERM" || code === "EACCES" || /EPERM|operation not permitted/i.test(message))) return undefined;
|
|
840
|
+
return `macOS privacy settings (TCC) block ${execPath} from reading Chrome's profile folder. ` +
|
|
841
|
+
`Grant it Full Disk Access: System Settings → Privacy & Security → Full Disk Access → +, press ⌘⇧G, paste ${execPath}, ` +
|
|
842
|
+
`then restart rech serve. Or run rech serve from Terminal, which already has access (see docs/macos-daemon.md).`;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** Why the last readChromeProfileCache() returned null (undefined when it succeeded). */
|
|
846
|
+
let profileCacheProblem: string | undefined;
|
|
847
|
+
|
|
830
848
|
export async function readChromeProfileCache(): Promise<Record<string, ChromeProfileInfo> | null> {
|
|
849
|
+
profileCacheProblem = undefined;
|
|
850
|
+
const problems: string[] = [];
|
|
831
851
|
for (const statePath of CHROME_LOCAL_STATE_PATHS()) {
|
|
832
852
|
const f = file(statePath);
|
|
833
853
|
if (!(await f.exists())) continue;
|
|
834
854
|
try {
|
|
835
855
|
const data = JSON.parse(await f.text());
|
|
836
|
-
|
|
837
|
-
|
|
856
|
+
if (data?.profile?.info_cache) return data.profile.info_cache;
|
|
857
|
+
problems.push(`${statePath} has no profile list`);
|
|
858
|
+
} catch (error) {
|
|
859
|
+
const hint = chromeDataAccessHint(error);
|
|
860
|
+
problems.push(`${statePath} is unreadable (${error instanceof Error ? error.message : String(error)})${hint ? `. ${hint}` : ""}`);
|
|
861
|
+
}
|
|
838
862
|
}
|
|
863
|
+
profileCacheProblem = problems.join("; ") || "Chrome's Local State file was not found";
|
|
839
864
|
return null;
|
|
840
865
|
}
|
|
841
866
|
|
|
867
|
+
/**
|
|
868
|
+
* Say so (once per process) when profile emails/names are unavailable, so a bare folder name
|
|
869
|
+
* like "Profile 1" is never mistaken for the whole story.
|
|
870
|
+
*/
|
|
871
|
+
let warnedProfileCache = false;
|
|
872
|
+
export function warnIfProfileNamesUnavailable(cache: Record<string, ChromeProfileInfo> | null): void {
|
|
873
|
+
if (cache || warnedProfileCache) return;
|
|
874
|
+
warnedProfileCache = true;
|
|
875
|
+
console.error(`[rech] Chrome profile emails and names are unavailable (${profileCacheProblem ?? "Local State not read"}); profiles are shown by folder name only.`);
|
|
876
|
+
}
|
|
877
|
+
|
|
842
878
|
export function resolveChromeProfileSelector(
|
|
843
879
|
profiles: Array<[string, ChromeProfileInfo]>,
|
|
844
880
|
selector: string,
|
|
@@ -1306,6 +1342,7 @@ async function listRemoteProfiles(url: string): Promise<void> {
|
|
|
1306
1342
|
|
|
1307
1343
|
async function listProfiles(): Promise<void> {
|
|
1308
1344
|
const [cache, registry, root] = await Promise.all([readChromeProfileCache(), readTokenRegistry(), findChromeUserDataDir()]);
|
|
1345
|
+
warnIfProfileNamesUnavailable(cache);
|
|
1309
1346
|
const profiles = buildProfileRows(cache, registry, root);
|
|
1310
1347
|
const listeners = await readListeners();
|
|
1311
1348
|
const url = process.env[ENV_KEY];
|
|
@@ -1405,7 +1442,7 @@ export function registeredProfileChoices(registry: Record<string, TokenEntry>, c
|
|
|
1405
1442
|
const info = !userDataDir || defaultDirs.includes(userDataDir) ? cache?.[dir] : undefined;
|
|
1406
1443
|
const names = [info?.name, info?.user_name, key].filter((n): n is string => !!n && n !== dir);
|
|
1407
1444
|
const shown = [...new Set(names)];
|
|
1408
|
-
return { label: shown.length ? `${shown.join(" · ")} [${dir}]` : dir
|
|
1445
|
+
return { label: shown.length ? `${shown.join(" · ")} [${dir}]` : `${dir} (no email or name known)`, value: key };
|
|
1409
1446
|
});
|
|
1410
1447
|
}
|
|
1411
1448
|
|
|
@@ -1639,6 +1676,7 @@ async function printProfileUri(selector?: string, listener?: string, opts: { loc
|
|
|
1639
1676
|
const interactive = isInteractive();
|
|
1640
1677
|
const registry = await readTokenRegistry();
|
|
1641
1678
|
const cache = await readChromeProfileCache();
|
|
1679
|
+
warnIfProfileNamesUnavailable(cache);
|
|
1642
1680
|
const cancelled = () => new Error("Cancelled; nothing shared.");
|
|
1643
1681
|
let config = await readListeners();
|
|
1644
1682
|
const current = resolveEffectiveProfile(url ? parseUrl(url).profileDirectory : undefined);
|
|
@@ -1808,6 +1846,7 @@ async function callServe(
|
|
|
1808
1846
|
overrideEnv?: Record<string, string>,
|
|
1809
1847
|
precomputedIdentity?: { key: string; label: string; profile?: string },
|
|
1810
1848
|
throwOnFailure = false,
|
|
1849
|
+
upload?: UploadPayload,
|
|
1811
1850
|
): Promise<{ status: number; stdout: string; stderr: string; files?: string[]; existingSession?: boolean }> {
|
|
1812
1851
|
const { key, host, port, protocol, extensionId, extensionToken, profileDirectory, userDataDir, loadExtension } = parseUrl(url);
|
|
1813
1852
|
// Reuse the caller's identity when provided — computing it shells out to `git` several times,
|
|
@@ -1826,7 +1865,7 @@ async function callServe(
|
|
|
1826
1865
|
method: "POST",
|
|
1827
1866
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
|
|
1828
1867
|
// dataDir is a client-local path; the daemon (possibly remote) only needs the session identity.
|
|
1829
|
-
body: JSON.stringify({ args, identity: { key: identity.key, label: identity.label, profile: identity.profile }, env }),
|
|
1868
|
+
body: JSON.stringify({ args, identity: { key: identity.key, label: identity.label, profile: identity.profile }, env, ...(upload ? { upload } : {}) }),
|
|
1830
1869
|
signal: AbortSignal.timeout(70_000),
|
|
1831
1870
|
}).catch(async (e) => {
|
|
1832
1871
|
if (throwOnFailure) throw new Error("Cannot reach the rechrome daemon. Check that it is running.");
|
|
@@ -1997,7 +2036,16 @@ export function unknownCommandHint(output: string, rechCommands: Iterable<string
|
|
|
1997
2036
|
].join("\n");
|
|
1998
2037
|
}
|
|
1999
2038
|
|
|
2000
|
-
|
|
2039
|
+
/**
|
|
2040
|
+
* An `open` whose extension bridge never connected. Typical right after Chrome restarts: the
|
|
2041
|
+
* relay's connect page reaches no live worker, yet a fresh bridge moments later connects at once
|
|
2042
|
+
* (seen 2026-10-17: a timeout, then `rech setup`'s probe connected in 0.1s). Worth one retry.
|
|
2043
|
+
*/
|
|
2044
|
+
export function isBridgeTimeout(args: string[], result: { status: number; stderr?: string }): boolean {
|
|
2045
|
+
return args.find(a => !a.startsWith("-")) === "open" && result.status !== 0 && /Extension connection timeout/i.test(result.stderr ?? "");
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
async function run(url: string, args: string[], overrideEnv?: Record<string, string>, opts: { verbatim?: boolean; bridgeRetried?: boolean } = {}) {
|
|
2001
2049
|
// Match the underlying CLI's command names while accepting the short forms humans
|
|
2002
2050
|
// naturally try. Keep this client-side so old and new serve daemons behave alike.
|
|
2003
2051
|
args = normalizeCommandArgs(args);
|
|
@@ -2012,7 +2060,19 @@ async function run(url: string, args: string[], overrideEnv?: Record<string, str
|
|
|
2012
2060
|
|
|
2013
2061
|
const resolvedEnv = await getClientEnv({ extensionId, extensionToken, profileDirectory: effectiveProfile, userDataDir, loadExtension });
|
|
2014
2062
|
const effectiveEnv = { ...resolvedEnv, ...overrideEnv };
|
|
2015
|
-
|
|
2063
|
+
let upload: UploadPayload | undefined;
|
|
2064
|
+
if (args.find(a => !/^-s=[a-zA-Z0-9_-]{1,64}$/.test(a)) === "upload") {
|
|
2065
|
+
if (process.stdin.isTTY) throw new Error("upload reads stdin; redirect a PNG/SVG file with < icon.png");
|
|
2066
|
+
({ args, upload } = await prepareStdinUpload(args, process.stdin));
|
|
2067
|
+
}
|
|
2068
|
+
const { status, stdout, stderr, files, existingSession } = await callServe(url, args, overrideEnv, identity, false, upload);
|
|
2069
|
+
if (!opts.bridgeRetried && isBridgeTimeout(args, { status, stderr })) {
|
|
2070
|
+
// Close the failed session so the retry gets a fresh cliDaemon and relay. callServe re-reads
|
|
2071
|
+
// the extension's live token from the profile, so a re-minted token heals here too.
|
|
2072
|
+
console.error(`[rech] the Chrome extension bridge did not answer (common right after Chrome restarts); retrying once with a fresh connection…`);
|
|
2073
|
+
await callServe(url, [...args.filter(a => /^-s=/.test(a)), "close"], overrideEnv, identity).catch(() => {});
|
|
2074
|
+
return run(url, args, overrideEnv, { ...opts, bridgeRetried: true });
|
|
2075
|
+
}
|
|
2016
2076
|
|
|
2017
2077
|
const isOpenWithUrl = args[0] === "open" && args.length > 1;
|
|
2018
2078
|
if (existingSession && isOpenWithUrl) {
|
|
@@ -2032,9 +2092,12 @@ async function run(url: string, args: string[], overrideEnv?: Record<string, str
|
|
|
2032
2092
|
// The daemon resolves registered profiles' bridge tokens itself and then asks for a reload;
|
|
2033
2093
|
// only blame a missing install when neither side had credentials.
|
|
2034
2094
|
const hasToken = !!effectiveEnv["PLAYWRIGHT_MCP_EXTENSION_TOKEN"] || /reload the .*extension/i.test(stderr);
|
|
2095
|
+
const profileArg = displayProfile ? ` --profile ${JSON.stringify(displayProfile)}` : "";
|
|
2035
2096
|
const last = hasToken
|
|
2036
|
-
? ` -x: extension did not connect (
|
|
2037
|
-
|
|
2097
|
+
? ` -x: extension did not connect${opts.bridgeRetried ? " (also after an automatic retry)" : ""} -> extension[degraded]\n` +
|
|
2098
|
+
`[rech] reload "Playwright MCP Bridge" at chrome://extensions${displayProfile ? ` in ${displayProfile}'s window` : ""}, then retry; ` +
|
|
2099
|
+
`or run \`rech setup${profileArg}\`, which re-detects the extension and token and verifies the connection.`
|
|
2100
|
+
: ` -> extension[not installed] (run: rech setup${profileArg})`;
|
|
2038
2101
|
console.error(`[rech] rech-client -> rech-server[ok] -> playwright[ok]\n${last}`);
|
|
2039
2102
|
}
|
|
2040
2103
|
if (stderr.includes("Browser '") && stderr.includes("is not open")) {
|
|
@@ -2069,6 +2132,26 @@ async function run(url: string, args: string[], overrideEnv?: Record<string, str
|
|
|
2069
2132
|
process.exit(status);
|
|
2070
2133
|
}
|
|
2071
2134
|
|
|
2135
|
+
/** The daemon's Playwright CLI predates `open --wait` (rechrome <= 1.35.1 bundled one). */
|
|
2136
|
+
export function cliRejectsWaitOption(output: string): boolean {
|
|
2137
|
+
return /Unknown options?:?[^\n]*?['"`]?--wait\b/i.test(output);
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
/**
|
|
2141
|
+
* setup's bridge probe: open about:blank without waiting for a load. The daemon owns the CLI and
|
|
2142
|
+
* may be older than this client, so feature-check by behavior: if the CLI rejects `--wait`, probe
|
|
2143
|
+
* again without it rather than reporting a broken bridge.
|
|
2144
|
+
*/
|
|
2145
|
+
export async function probeBridgeOpen<T extends { status: number; stdout: string; stderr: string }>(
|
|
2146
|
+
call: (args: string[]) => Promise<T>,
|
|
2147
|
+
note: (message: string) => void = () => {},
|
|
2148
|
+
): Promise<T> {
|
|
2149
|
+
const probe = await call(["open", "about:blank", "--wait", "none"]);
|
|
2150
|
+
if (probe.status === 0 || !cliRejectsWaitOption(`${probe.stderr}\n${probe.stdout}`)) return probe;
|
|
2151
|
+
note("The daemon's Playwright CLI does not support `open --wait`; probing without it (update rechrome on the daemon host).");
|
|
2152
|
+
return call(["open", "about:blank"]);
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2072
2155
|
export type SetupPhase = "extension" | "token" | "bridge" | "error" | "save" | "ready";
|
|
2073
2156
|
|
|
2074
2157
|
export function createSetupGuide(extDistDir: string, profileDisplay: string) {
|
|
@@ -2529,6 +2612,7 @@ export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
2529
2612
|
[ENV_KEY]: serveUrl,
|
|
2530
2613
|
PWMCP_TEST_CONNECTION_TIMEOUT: process.env.PWMCP_TEST_CONNECTION_TIMEOUT || "30000",
|
|
2531
2614
|
PLAYWRIGHT_CLI: resolvedPlaywrightCli,
|
|
2615
|
+
RECH_SERVE_MANAGED: "1", // the manager restarts it; never idle-self-exit (see serve.ts)
|
|
2532
2616
|
};
|
|
2533
2617
|
if (process.env.RECH_HOST) daemonEnv.RECH_HOST = process.env.RECH_HOST;
|
|
2534
2618
|
if (isReadable(process.env.RECH_TLS_CERT)) daemonEnv.RECH_TLS_CERT = process.env.RECH_TLS_CERT!;
|
|
@@ -3287,7 +3371,7 @@ async function setup(opts: SetupOptions = {}): Promise<void> {
|
|
|
3287
3371
|
console.log(`✓ [1/5] Local management daemon verified; requested profile access: ${desiredBind}`);
|
|
3288
3372
|
|
|
3289
3373
|
const cache = await readChromeProfileCache();
|
|
3290
|
-
if (!cache) { console.error(
|
|
3374
|
+
if (!cache) { console.error(` Chrome profiles not found: ${profileCacheProblem ?? "Local State not read"}`); rl?.close(); process.exit(1); }
|
|
3291
3375
|
const userDataDir = await findChromeUserDataDir();
|
|
3292
3376
|
|
|
3293
3377
|
async function pickProfile(exclude: Set<string>): Promise<[string, ChromeProfileInfo] | null> {
|
|
@@ -3413,12 +3497,9 @@ async function setup(opts: SetupOptions = {}): Promise<void> {
|
|
|
3413
3497
|
guide?.takeRetry();
|
|
3414
3498
|
guide?.update("bridge", "Extension and token detected. Testing the browser connection…");
|
|
3415
3499
|
try {
|
|
3416
|
-
const probe = await
|
|
3417
|
-
rechUrl.toString(),
|
|
3418
|
-
|
|
3419
|
-
probeEnv,
|
|
3420
|
-
probeIdentity,
|
|
3421
|
-
true,
|
|
3500
|
+
const probe = await probeBridgeOpen(
|
|
3501
|
+
args => callServe(rechUrl.toString(), [`-s=${probeSession}`, ...args], probeEnv, probeIdentity, true),
|
|
3502
|
+
note => console.log(` ${note}`),
|
|
3422
3503
|
);
|
|
3423
3504
|
bridgeVerified = probe.status === 0;
|
|
3424
3505
|
if (bridgeVerified) {
|
|
@@ -3574,7 +3655,7 @@ async function status(): Promise<void> {
|
|
|
3574
3655
|
? await fetch(serviceUrl(url, "ping"), { headers: { Authorization: `Bearer ${parsed.key}` }, signal: AbortSignal.timeout(2000) }).catch(() => null)
|
|
3575
3656
|
: null;
|
|
3576
3657
|
const pingBody = pingResponse?.ok
|
|
3577
|
-
? await pingResponse.json().catch(() => null) as { bind?: string; listener?: string; profiles?: string[] | "*"; degraded?: boolean; consecutiveTimeouts?: number } | null
|
|
3658
|
+
? await pingResponse.json().catch(() => null) as { bind?: string; listener?: string; profiles?: string[] | "*"; degraded?: boolean; consecutiveTimeouts?: number; chromeAccessProblem?: string } | null
|
|
3578
3659
|
: null;
|
|
3579
3660
|
// Show the URL this client connects to; through a proxy, the daemon's bind is on another port.
|
|
3580
3661
|
const details = [pingBody?.listener && `listener ${pingBody.listener}`, pingBody?.bind && `bind ${pingBody.bind}`].filter(Boolean).join(", ");
|
|
@@ -3595,6 +3676,8 @@ async function status(): Promise<void> {
|
|
|
3595
3676
|
// No oxmgr/pm2 on PATH must not take down `rech status`: report it instead of throwing.
|
|
3596
3677
|
let mgr: DaemonManager | undefined;
|
|
3597
3678
|
if (isHost) try { mgr = daemonManager(); } catch { /* reported below */ }
|
|
3679
|
+
if (pingBody?.chromeAccessProblem)
|
|
3680
|
+
console.log(`chrome: ⚠ daemon ${pingBody.chromeAccessProblem}`);
|
|
3598
3681
|
if (pingBody?.degraded)
|
|
3599
3682
|
console.log(`relay: ⚠ degraded (${pingBody.consecutiveTimeouts} consecutive command timeouts) — if it persists, the daemon self-restarts; ${isHost ? `force it now with \`${mgr?.id ?? "oxmgr"} restart ${PM_PROCESS_NAME}\`` : "the daemon host can restart it"}`);
|
|
3600
3683
|
if (isHost) {
|
|
@@ -3658,6 +3741,7 @@ const HELP_EPILOGUE = `Browser commands (sent to this project's Chrome session):
|
|
|
3658
3741
|
|
|
3659
3742
|
Environment:
|
|
3660
3743
|
${ENV_KEY} connection URL; read from the nearest .rechrome/.env.local or .env.local
|
|
3744
|
+
RECHROME_PROFILE default browser profile selector; --profile overrides it
|
|
3661
3745
|
RECH_IDENTITY session key: worktree (default) | branch | cwd
|
|
3662
3746
|
RECH_TOKEN extension token for \`rech setup\` (same as --token)
|
|
3663
3747
|
RECH_SETUP_AGENT setup hints: codex | claude | none (auto-detected)
|
|
@@ -3848,7 +3932,7 @@ if (import.meta.main) {
|
|
|
3848
3932
|
if (separator !== -1) args = args.slice(0, separator);
|
|
3849
3933
|
try {
|
|
3850
3934
|
const extracted = extractGlobalProfileArg(args);
|
|
3851
|
-
profileSelector = extracted.selector;
|
|
3935
|
+
profileSelector = extracted.selector ?? (process.env.RECHROME_PROFILE?.trim() || undefined);
|
|
3852
3936
|
args = extracted.args;
|
|
3853
3937
|
} catch (err) {
|
|
3854
3938
|
console.error(err instanceof Error ? err.message : String(err));
|
package/scoped-upload.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// scoped-upload.ts
|
|
3
|
+
import { createHash, randomBytes } from "crypto";
|
|
4
|
+
import { mkdtemp, writeFile, rm } from "fs/promises";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
var MAX_UPLOAD_BYTES = 2 * 1024 * 1024;
|
|
8
|
+
var MAX_REQUEST_BYTES = 3 * 1024 * 1024;
|
|
9
|
+
var UPLOAD_TYPES = ["image/png", "image/svg+xml"];
|
|
10
|
+
function validateUploadPolicy(value) {
|
|
11
|
+
const p = value;
|
|
12
|
+
if (!p || typeof p !== "object" || Array.isArray(p) || Object.keys(p).some((k) => !["maxBytes", "contentTypes"].includes(k)) || p.maxBytes !== undefined && (!Number.isSafeInteger(p.maxBytes) || p.maxBytes < 1 || p.maxBytes > MAX_UPLOAD_BYTES) || p.contentTypes !== undefined && (!Array.isArray(p.contentTypes) || !p.contentTypes.length || p.contentTypes.some((t) => !UPLOAD_TYPES.includes(t))))
|
|
13
|
+
throw new Error("uploads must be an object with optional maxBytes (1..2097152) and contentTypes (image/png, image/svg+xml)");
|
|
14
|
+
}
|
|
15
|
+
function validName(name) {
|
|
16
|
+
return typeof name === "string" && name.length > 0 && name.length <= 128 && name !== "." && name !== ".." && !name.startsWith("-") && !/[\\/:\x00-\x1f\x7f]/.test(name);
|
|
17
|
+
}
|
|
18
|
+
function matchesType(bytes, type) {
|
|
19
|
+
if (type === "image/png")
|
|
20
|
+
return bytes.length >= 33 && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) && bytes.readUInt32BE(8) === 13 && bytes.toString("ascii", 12, 16) === "IHDR";
|
|
21
|
+
if (type === "image/svg+xml") {
|
|
22
|
+
let text;
|
|
23
|
+
try {
|
|
24
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (/<!DOCTYPE|<!ENTITY/i.test(text))
|
|
29
|
+
return false;
|
|
30
|
+
text = text.trim().replace(/^<\?xml\s[^?]*\?>\s*/, "").replace(/^(?:<!--[\s\S]*?-->\s*)+/, "");
|
|
31
|
+
return /^<svg(?:\s|\/?>)/.test(text) && /(?:<\/svg\s*>|\/>)\s*$/.test(text);
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
async function prepareStdinUpload(args, input) {
|
|
36
|
+
const sessions = args.filter((a) => /^-s=[a-zA-Z0-9_-]{1,64}$/.test(a));
|
|
37
|
+
const options = args.filter((a) => !sessions.includes(a));
|
|
38
|
+
if (options.shift() !== "upload")
|
|
39
|
+
throw new Error("Expected upload command");
|
|
40
|
+
const fields = {};
|
|
41
|
+
while (options.length) {
|
|
42
|
+
const option = options.shift();
|
|
43
|
+
const match = option.match(/^--(name|content-type)(?:=(.*))?$/);
|
|
44
|
+
if (!match || fields[match[1]] !== undefined)
|
|
45
|
+
throw new Error("Usage: rech upload --name icon.png [--content-type image/png] < icon.png (stdin only; no path argument)");
|
|
46
|
+
const value = match[2] ?? options.shift();
|
|
47
|
+
if (!value || value.startsWith("--"))
|
|
48
|
+
throw new Error(`Missing value for --${match[1]}`);
|
|
49
|
+
fields[match[1]] = value;
|
|
50
|
+
}
|
|
51
|
+
if (!validName(fields.name))
|
|
52
|
+
throw new Error("upload requires --name with a plain filename (no path)");
|
|
53
|
+
const contentType = fields["content-type"] ?? (fields.name.toLowerCase().endsWith(".png") ? "image/png" : fields.name.toLowerCase().endsWith(".svg") ? "image/svg+xml" : "");
|
|
54
|
+
if (!UPLOAD_TYPES.includes(contentType))
|
|
55
|
+
throw new Error("Upload content type must be image/png or image/svg+xml");
|
|
56
|
+
const chunks = [];
|
|
57
|
+
let size = 0;
|
|
58
|
+
for await (const chunk of input) {
|
|
59
|
+
size += chunk.byteLength;
|
|
60
|
+
if (size > MAX_UPLOAD_BYTES)
|
|
61
|
+
throw new Error("Upload exceeds 2 MiB");
|
|
62
|
+
chunks.push(Buffer.from(chunk));
|
|
63
|
+
}
|
|
64
|
+
const bytes = Buffer.concat(chunks);
|
|
65
|
+
if (!matchesType(bytes, contentType))
|
|
66
|
+
throw new Error("Upload bytes do not match the content type (PNG or UTF-8 SVG without DTD/entities required)");
|
|
67
|
+
return { args: ["upload", ...sessions], upload: { name: fields.name, contentType, data: bytes.toString("base64") } };
|
|
68
|
+
}
|
|
69
|
+
function currentPageOrigin(output) {
|
|
70
|
+
const current = output.split(`
|
|
71
|
+
`).filter((line) => /^- \d+: \(current\) /.test(line));
|
|
72
|
+
const url = current.length === 1 ? current[0].match(/\]\((.*)\)(?: \[crashed\])?$/)?.[1] : undefined;
|
|
73
|
+
if (!url)
|
|
74
|
+
throw new Error("Could not determine the upload page origin");
|
|
75
|
+
const parsed = new URL(url);
|
|
76
|
+
if (!["http:", "https:"].includes(parsed.protocol))
|
|
77
|
+
throw new Error("Uploads require an HTTP(S) page");
|
|
78
|
+
return parsed.origin;
|
|
79
|
+
}
|
|
80
|
+
async function receiveUpload(options) {
|
|
81
|
+
const record = { name: null, size: null, sha256: null, origin: null, result: "rejected" };
|
|
82
|
+
let dir;
|
|
83
|
+
try {
|
|
84
|
+
const p = options.payload;
|
|
85
|
+
if (validName(p?.name))
|
|
86
|
+
record.name = p.name;
|
|
87
|
+
if (options.policy === undefined)
|
|
88
|
+
throw new Error("Uploads are disabled on this listener");
|
|
89
|
+
validateUploadPolicy(options.policy);
|
|
90
|
+
if (options.args.length !== 1 || options.args[0] !== "upload")
|
|
91
|
+
throw new Error("Upload takes stdin bytes, not host paths or CLI options");
|
|
92
|
+
if (!p || !validName(p.name) || typeof p.contentType !== "string" || typeof p.data !== "string" || Object.keys(p).some((k) => !["name", "contentType", "data"].includes(k)))
|
|
93
|
+
throw new Error("Invalid upload payload");
|
|
94
|
+
const limit = options.policy.maxBytes ?? MAX_UPLOAD_BYTES;
|
|
95
|
+
if (p.data.length > 4 * Math.ceil(limit / 3) || /[^A-Za-z0-9+/=]/.test(p.data))
|
|
96
|
+
throw new Error("Upload exceeds maxBytes or has invalid base64");
|
|
97
|
+
const bytes = Buffer.from(p.data, "base64");
|
|
98
|
+
record.size = bytes.length;
|
|
99
|
+
record.sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
100
|
+
if (!bytes.length || bytes.length > limit || bytes.toString("base64") !== p.data)
|
|
101
|
+
throw new Error("Upload is empty, exceeds maxBytes, or is not canonical base64");
|
|
102
|
+
if (!(options.policy.contentTypes ?? UPLOAD_TYPES).includes(p.contentType) || !matchesType(bytes, p.contentType))
|
|
103
|
+
throw new Error("Upload content type is not allowed or does not match the bytes");
|
|
104
|
+
const tabs = await options.run(["tab-list"]);
|
|
105
|
+
if (tabs.status !== 0)
|
|
106
|
+
throw new Error("Could not inspect the upload page");
|
|
107
|
+
record.origin = currentPageOrigin(tabs.stdout);
|
|
108
|
+
dir = await mkdtemp(join(tmpdir(), "rech-upload-"));
|
|
109
|
+
const path = join(dir, randomBytes(16).toString("hex") + (p.contentType === "image/png" ? ".png" : ".svg"));
|
|
110
|
+
await writeFile(path, bytes, { mode: 384, flag: "wx" });
|
|
111
|
+
record.result = "failed";
|
|
112
|
+
const result = await options.run(["upload", path]);
|
|
113
|
+
record.result = result.status === 0 && !/^### Error\b/m.test(result.stdout) ? "completed" : "failed";
|
|
114
|
+
return {
|
|
115
|
+
...result,
|
|
116
|
+
status: record.result === "completed" ? 0 : 1,
|
|
117
|
+
stdout: result.stdout.replaceAll(path, p.name),
|
|
118
|
+
stderr: result.stderr.replaceAll(path, p.name)
|
|
119
|
+
};
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return { status: 1, stdout: "", stderr: (error instanceof Error ? error.message : "Upload failed") + `
|
|
122
|
+
` };
|
|
123
|
+
} finally {
|
|
124
|
+
try {
|
|
125
|
+
if (dir)
|
|
126
|
+
await rm(dir, { recursive: true, force: true });
|
|
127
|
+
} finally {
|
|
128
|
+
options.audit(record);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function readRequestJson(req) {
|
|
133
|
+
const reader = req.body?.getReader();
|
|
134
|
+
if (!reader)
|
|
135
|
+
throw new Error("Empty request");
|
|
136
|
+
const chunks = [];
|
|
137
|
+
let size = 0;
|
|
138
|
+
try {
|
|
139
|
+
for (;; ) {
|
|
140
|
+
const { done, value } = await reader.read();
|
|
141
|
+
if (done)
|
|
142
|
+
break;
|
|
143
|
+
size += value.byteLength;
|
|
144
|
+
if (size > MAX_REQUEST_BYTES)
|
|
145
|
+
throw new Error("Request exceeds 3 MiB");
|
|
146
|
+
chunks.push(value);
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
await reader.cancel().catch(() => {});
|
|
150
|
+
throw error;
|
|
151
|
+
} finally {
|
|
152
|
+
reader.releaseLock();
|
|
153
|
+
}
|
|
154
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
155
|
+
}
|
|
156
|
+
export {
|
|
157
|
+
MAX_REQUEST_BYTES,
|
|
158
|
+
MAX_UPLOAD_BYTES,
|
|
159
|
+
UPLOAD_TYPES,
|
|
160
|
+
currentPageOrigin,
|
|
161
|
+
prepareStdinUpload,
|
|
162
|
+
readRequestJson,
|
|
163
|
+
receiveUpload,
|
|
164
|
+
validateUploadPolicy
|
|
165
|
+
};
|
package/scoped-upload.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
|
|
6
|
+
export const MAX_UPLOAD_BYTES = 2 * 1024 * 1024;
|
|
7
|
+
// Base64 plus metadata. Bound JSON input before parsing, not just decoded bytes.
|
|
8
|
+
export const MAX_REQUEST_BYTES = 3 * 1024 * 1024;
|
|
9
|
+
export const UPLOAD_TYPES = ['image/png', 'image/svg+xml'] as const;
|
|
10
|
+
export type UploadPolicy = { maxBytes?: number; contentTypes?: string[] };
|
|
11
|
+
export type UploadPayload = { name: string; contentType: string; data: string };
|
|
12
|
+
export type UploadResult = { status: number; stdout: string; stderr: string };
|
|
13
|
+
export type UploadAudit = { name: string | null; size: number | null; sha256: string | null; origin: string | null; result: string };
|
|
14
|
+
|
|
15
|
+
export function validateUploadPolicy(value: unknown): asserts value is UploadPolicy {
|
|
16
|
+
const p = value as UploadPolicy;
|
|
17
|
+
if (!p || typeof p !== 'object' || Array.isArray(p) || Object.keys(p).some(k => !['maxBytes', 'contentTypes'].includes(k))
|
|
18
|
+
|| (p.maxBytes !== undefined && (!Number.isSafeInteger(p.maxBytes) || p.maxBytes < 1 || p.maxBytes > MAX_UPLOAD_BYTES))
|
|
19
|
+
|| (p.contentTypes !== undefined && (!Array.isArray(p.contentTypes) || !p.contentTypes.length || p.contentTypes.some(t => !UPLOAD_TYPES.includes(t as any)))))
|
|
20
|
+
throw new Error('uploads must be an object with optional maxBytes (1..2097152) and contentTypes (image/png, image/svg+xml)');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function validName(name: unknown): name is string {
|
|
24
|
+
return typeof name === 'string' && name.length > 0 && name.length <= 128
|
|
25
|
+
&& name !== '.' && name !== '..' && !name.startsWith('-') && !/[\\/:\x00-\x1f\x7f]/.test(name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function matchesType(bytes: Buffer, type: string): boolean {
|
|
29
|
+
if (type === 'image/png') return bytes.length >= 33 && bytes.subarray(0, 8).equals(Buffer.from([137,80,78,71,13,10,26,10]))
|
|
30
|
+
&& bytes.readUInt32BE(8) === 13 && bytes.toString('ascii', 12, 16) === 'IHDR';
|
|
31
|
+
if (type === 'image/svg+xml') {
|
|
32
|
+
let text: string;
|
|
33
|
+
try { text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); } catch { return false; }
|
|
34
|
+
// Sniff only; never parse/render SVG or resolve XML entities on the host.
|
|
35
|
+
if (/<!DOCTYPE|<!ENTITY/i.test(text)) return false;
|
|
36
|
+
text = text.trim().replace(/^<\?xml\s[^?]*\?>\s*/, '').replace(/^(?:<!--[\s\S]*?-->\s*)+/, '');
|
|
37
|
+
return /^<svg(?:\s|\/?>)/.test(text) && /(?:<\/svg\s*>|\/>)\s*$/.test(text);
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function prepareStdinUpload(args: string[], input: AsyncIterable<Uint8Array>): Promise<{ args: string[]; upload: UploadPayload }> {
|
|
43
|
+
const sessions = args.filter(a => /^-s=[a-zA-Z0-9_-]{1,64}$/.test(a));
|
|
44
|
+
const options = args.filter(a => !sessions.includes(a));
|
|
45
|
+
if (options.shift() !== 'upload') throw new Error('Expected upload command');
|
|
46
|
+
const fields: Record<string, string> = {};
|
|
47
|
+
while (options.length) {
|
|
48
|
+
const option = options.shift()!;
|
|
49
|
+
const match = option.match(/^--(name|content-type)(?:=(.*))?$/);
|
|
50
|
+
if (!match || fields[match[1]] !== undefined) throw new Error('Usage: rech upload --name icon.png [--content-type image/png] < icon.png (stdin only; no path argument)');
|
|
51
|
+
const value = match[2] ?? options.shift();
|
|
52
|
+
if (!value || value.startsWith('--')) throw new Error(`Missing value for --${match[1]}`);
|
|
53
|
+
fields[match[1]] = value;
|
|
54
|
+
}
|
|
55
|
+
if (!validName(fields.name)) throw new Error('upload requires --name with a plain filename (no path)');
|
|
56
|
+
const contentType = fields['content-type'] ?? (fields.name.toLowerCase().endsWith('.png') ? 'image/png' : fields.name.toLowerCase().endsWith('.svg') ? 'image/svg+xml' : '');
|
|
57
|
+
if (!UPLOAD_TYPES.includes(contentType as any)) throw new Error('Upload content type must be image/png or image/svg+xml');
|
|
58
|
+
const chunks: Buffer[] = [];
|
|
59
|
+
let size = 0;
|
|
60
|
+
for await (const chunk of input) {
|
|
61
|
+
size += chunk.byteLength;
|
|
62
|
+
if (size > MAX_UPLOAD_BYTES) throw new Error('Upload exceeds 2 MiB');
|
|
63
|
+
chunks.push(Buffer.from(chunk));
|
|
64
|
+
}
|
|
65
|
+
const bytes = Buffer.concat(chunks);
|
|
66
|
+
if (!matchesType(bytes, contentType)) throw new Error('Upload bytes do not match the content type (PNG or UTF-8 SVG without DTD/entities required)');
|
|
67
|
+
return { args: ['upload', ...sessions], upload: { name: fields.name, contentType, data: bytes.toString('base64') } };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function currentPageOrigin(output: string): string {
|
|
71
|
+
const current = output.split('\n').filter(line => /^- \d+: \(current\) /.test(line));
|
|
72
|
+
const url = current.length === 1 ? current[0].match(/\]\((.*)\)(?: \[crashed\])?$/)?.[1] : undefined;
|
|
73
|
+
if (!url) throw new Error('Could not determine the upload page origin');
|
|
74
|
+
const parsed = new URL(url);
|
|
75
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) throw new Error('Uploads require an HTTP(S) page');
|
|
76
|
+
return parsed.origin;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** No payload field is ever used as a host path. run() is a server-owned CLI runner,
|
|
80
|
+
* not caller-supplied code. Audit records the selected origin immediately before upload.
|
|
81
|
+
*/
|
|
82
|
+
export async function receiveUpload(options: {
|
|
83
|
+
policy: UploadPolicy | undefined; payload: unknown; args: string[];
|
|
84
|
+
run: (args: string[]) => Promise<UploadResult>; audit: (event: UploadAudit) => void;
|
|
85
|
+
}): Promise<UploadResult> {
|
|
86
|
+
const record: UploadAudit = { name: null, size: null, sha256: null, origin: null, result: 'rejected' };
|
|
87
|
+
let dir: string | undefined;
|
|
88
|
+
try {
|
|
89
|
+
const p = options.payload as UploadPayload;
|
|
90
|
+
if (validName(p?.name)) record.name = p.name;
|
|
91
|
+
if (options.policy === undefined) throw new Error('Uploads are disabled on this listener');
|
|
92
|
+
validateUploadPolicy(options.policy);
|
|
93
|
+
if (options.args.length !== 1 || options.args[0] !== 'upload') throw new Error('Upload takes stdin bytes, not host paths or CLI options');
|
|
94
|
+
if (!p || !validName(p.name) || typeof p.contentType !== 'string' || typeof p.data !== 'string'
|
|
95
|
+
|| Object.keys(p).some(k => !['name', 'contentType', 'data'].includes(k))) throw new Error('Invalid upload payload');
|
|
96
|
+
const limit = options.policy.maxBytes ?? MAX_UPLOAD_BYTES;
|
|
97
|
+
if (p.data.length > 4 * Math.ceil(limit / 3) || /[^A-Za-z0-9+/=]/.test(p.data))
|
|
98
|
+
throw new Error('Upload exceeds maxBytes or has invalid base64');
|
|
99
|
+
const bytes = Buffer.from(p.data, 'base64');
|
|
100
|
+
record.size = bytes.length;
|
|
101
|
+
record.sha256 = createHash('sha256').update(bytes).digest('hex');
|
|
102
|
+
if (!bytes.length || bytes.length > limit || bytes.toString('base64') !== p.data) throw new Error('Upload is empty, exceeds maxBytes, or is not canonical base64');
|
|
103
|
+
if (!(options.policy.contentTypes ?? UPLOAD_TYPES).includes(p.contentType) || !matchesType(bytes, p.contentType))
|
|
104
|
+
throw new Error('Upload content type is not allowed or does not match the bytes');
|
|
105
|
+
const tabs = await options.run(['tab-list']);
|
|
106
|
+
if (tabs.status !== 0) throw new Error('Could not inspect the upload page');
|
|
107
|
+
record.origin = currentPageOrigin(tabs.stdout);
|
|
108
|
+
dir = await mkdtemp(join(tmpdir(), 'rech-upload-')); // 0700; never served by /files
|
|
109
|
+
const path = join(dir, randomBytes(16).toString('hex') + (p.contentType === 'image/png' ? '.png' : '.svg'));
|
|
110
|
+
await writeFile(path, bytes, { mode: 0o600, flag: 'wx' });
|
|
111
|
+
record.result = 'failed';
|
|
112
|
+
const result = await options.run(['upload', path]);
|
|
113
|
+
record.result = result.status === 0 && !/^### Error\b/m.test(result.stdout) ? 'completed' : 'failed';
|
|
114
|
+
return { ...result, status: record.result === 'completed' ? 0 : 1,
|
|
115
|
+
stdout: result.stdout.replaceAll(path, p.name), stderr: result.stderr.replaceAll(path, p.name) };
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return { status: 1, stdout: '', stderr: (error instanceof Error ? error.message : 'Upload failed') + '\n' };
|
|
118
|
+
} finally {
|
|
119
|
+
try { if (dir) await rm(dir, { recursive: true, force: true }); }
|
|
120
|
+
finally { options.audit(record); }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function readRequestJson(req: Request): Promise<any> {
|
|
125
|
+
const reader = req.body?.getReader();
|
|
126
|
+
if (!reader) throw new Error('Empty request');
|
|
127
|
+
const chunks: Uint8Array[] = [];
|
|
128
|
+
let size = 0;
|
|
129
|
+
try {
|
|
130
|
+
for (;;) {
|
|
131
|
+
const { done, value } = await reader.read();
|
|
132
|
+
if (done) break;
|
|
133
|
+
size += value.byteLength;
|
|
134
|
+
if (size > MAX_REQUEST_BYTES) throw new Error('Request exceeds 3 MiB');
|
|
135
|
+
chunks.push(value);
|
|
136
|
+
}
|
|
137
|
+
} catch (error) { await reader.cancel().catch(() => {}); throw error; }
|
|
138
|
+
finally { reader.releaseLock(); }
|
|
139
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
140
|
+
}
|