@lowdefy/server-dev 6.1.0 → 7.0.0
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/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +67 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +679 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/findCollectionCollisions.js +52 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +44 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +119 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +343 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +68 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +220 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +33 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +203 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +8 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +54 -6
- package/lib/docs/getBuildStatus.test.mjs +133 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +83 -0
- package/lib/server/applyDataSetRedirect.test.mjs +340 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +204 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +131 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +328 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +112 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +24 -2
- package/manager/processes/initialBuild.mjs +14 -0
- package/manager/processes/initialBuild.test.mjs +101 -0
- package/manager/processes/lowdefyBuild.mjs +30 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +62 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -28,10 +28,31 @@ function formatFeedback({ items }) {
|
|
|
28
28
|
return items.map(formatBatch).join('\n\n---\n\n');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// A page with placeholders in its path names the instance by its values.
|
|
32
|
+
function hasPathParams(batch) {
|
|
33
|
+
return Object.keys(batch.pathParams ?? {}).length > 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function describePage(batch) {
|
|
37
|
+
if (!hasPathParams(batch)) {
|
|
38
|
+
return `page "${batch.pageId}"`;
|
|
39
|
+
}
|
|
40
|
+
return `page "${batch.pageId}" with pathParams ${JSON.stringify(batch.pathParams)}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function inspectStateCall(batch) {
|
|
44
|
+
if (!hasPathParams(batch)) {
|
|
45
|
+
return `lowdefy_inspect_state({ pageId: "${batch.pageId}" })`;
|
|
46
|
+
}
|
|
47
|
+
return `lowdefy_inspect_state({ pageId: "${batch.pageId}", pathParams: ${JSON.stringify(
|
|
48
|
+
batch.pathParams
|
|
49
|
+
)} })`;
|
|
50
|
+
}
|
|
51
|
+
|
|
31
52
|
function formatBatch(batch) {
|
|
32
53
|
const viewport = batch.viewport ?? {};
|
|
33
54
|
const lines = [
|
|
34
|
-
`Feedback: ${batch.annotations?.length ?? 0} annotation(s) on
|
|
55
|
+
`Feedback: ${batch.annotations?.length ?? 0} annotation(s) on ${describePage(batch)} ` +
|
|
35
56
|
`(${batch.url ?? 'unknown url'}) — viewport ${viewport.width}x${viewport.height} ` +
|
|
36
57
|
`@${viewport.dpr ?? 1}x, scrollY ${viewport.scrollY ?? 0}`,
|
|
37
58
|
'',
|
|
@@ -43,13 +64,13 @@ function formatBatch(batch) {
|
|
|
43
64
|
|
|
44
65
|
if (batch.screenshotPath) {
|
|
45
66
|
lines.push('');
|
|
46
|
-
lines.push(
|
|
67
|
+
lines.push(
|
|
68
|
+
`Annotated screenshot: ${batch.screenshotPath} (read this image to see the drawings)`
|
|
69
|
+
);
|
|
47
70
|
}
|
|
48
71
|
|
|
49
72
|
lines.push('');
|
|
50
|
-
lines.push(
|
|
51
|
-
`For the page's live state call lowdefy_inspect_state({ pageId: "${batch.pageId}" }).`
|
|
52
|
-
);
|
|
73
|
+
lines.push(`For the page's live state call ${inspectStateCall(batch)}.`);
|
|
53
74
|
|
|
54
75
|
return lines.join('\n');
|
|
55
76
|
}
|
|
@@ -202,3 +202,51 @@ test('formatFeedback multiple batches are joined and each keeps its own pageId i
|
|
|
202
202
|
expect(text).toContain('lowdefy_inspect_state({ pageId: "login" })');
|
|
203
203
|
expect(text).toContain('lowdefy_inspect_state({ pageId: "home" })');
|
|
204
204
|
});
|
|
205
|
+
|
|
206
|
+
test('formatFeedback names the page instance by its pathParams', () => {
|
|
207
|
+
const text = formatFeedback({
|
|
208
|
+
items: [
|
|
209
|
+
{
|
|
210
|
+
pageId: 'ticket',
|
|
211
|
+
pathParams: { space: 's', ticket_id: '1' },
|
|
212
|
+
url: '/tickets/s/1',
|
|
213
|
+
viewport: { width: 100, height: 100 },
|
|
214
|
+
annotations: [],
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
});
|
|
218
|
+
expect(text).toContain(
|
|
219
|
+
'Feedback: 0 annotation(s) on page "ticket" with pathParams {"space":"s","ticket_id":"1"} (/tickets/s/1)'
|
|
220
|
+
);
|
|
221
|
+
expect(text).toContain(
|
|
222
|
+
'lowdefy_inspect_state({ pageId: "ticket", pathParams: {"space":"s","ticket_id":"1"} })'
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('formatFeedback leaves empty pathParams out', () => {
|
|
227
|
+
const text = formatFeedback({
|
|
228
|
+
items: [
|
|
229
|
+
{
|
|
230
|
+
pageId: 'home',
|
|
231
|
+
pathParams: {},
|
|
232
|
+
url: '/home',
|
|
233
|
+
viewport: { width: 100, height: 100 },
|
|
234
|
+
annotations: [],
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
});
|
|
238
|
+
expect(text).toContain('Feedback: 0 annotation(s) on page "home" (/home)');
|
|
239
|
+
expect(text).toContain('lowdefy_inspect_state({ pageId: "home" })');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test('enrichFeedback keeps the batch pathParams', async () => {
|
|
243
|
+
const enriched = await enrichFeedback({
|
|
244
|
+
batch: {
|
|
245
|
+
pageId: 'ticket',
|
|
246
|
+
pathParams: { space: 's', ticket_id: '1' },
|
|
247
|
+
urlQuery: '',
|
|
248
|
+
annotations: [],
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
expect(enriched.pathParams).toEqual({ space: 's', ticket_id: '1' });
|
|
252
|
+
});
|
package/lib/docs/getAppMap.js
CHANGED
|
@@ -58,8 +58,13 @@ function summarizeRequests({ pageId, requests }) {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// A page's `path` is the URL pattern it is served at (its id when it declares
|
|
62
|
+
// none). A pattern with placeholders, e.g. "tickets/{space}/{ticket_id}", needs
|
|
63
|
+
// `pathParams` to open in the page tools.
|
|
61
64
|
function getPages() {
|
|
62
65
|
const registry = readBuildArtifact({ name: 'pageRegistry.json' }) ?? {};
|
|
66
|
+
const routes = readBuildArtifact({ name: 'routes.json', deserialize: true });
|
|
67
|
+
const pathByPageId = new Map(routes.map((route) => [route.pageId, route.path]));
|
|
63
68
|
const pages = [];
|
|
64
69
|
let unbuiltCount = 0;
|
|
65
70
|
|
|
@@ -67,6 +72,7 @@ function getPages() {
|
|
|
67
72
|
const built = readBuildArtifact({ name: `pages/${pageId}.json`, deserialize: true });
|
|
68
73
|
const page = {
|
|
69
74
|
pageId,
|
|
75
|
+
path: pathByPageId.get(pageId),
|
|
70
76
|
file: entry.refPath,
|
|
71
77
|
auth: entry.auth,
|
|
72
78
|
built: !type.isNone(built),
|
|
@@ -170,7 +176,7 @@ function getAppMap() {
|
|
|
170
176
|
if (unbuiltCount > 0) {
|
|
171
177
|
map.note =
|
|
172
178
|
`${unbuiltCount} page(s) have not been built yet, so only "file" and "auth" are shown ` +
|
|
173
|
-
'for them. Visit the page in the browser, or GET /lowdefy-docs/page/{pageId}, to trigger ' +
|
|
179
|
+
'for them. Visit the page in the browser, or GET /lowdefy-docs/page-config/{pageId}, to trigger ' +
|
|
174
180
|
'a build and see their blocks and requests.';
|
|
175
181
|
}
|
|
176
182
|
|
package/lib/docs/getBrowser.js
CHANGED
|
@@ -14,58 +14,42 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import { buildPagePath, type, urlQuery as urlQueryFn } from '@lowdefy/helpers';
|
|
19
18
|
|
|
20
19
|
import lowdefyConfig from '../build/config.js';
|
|
20
|
+
import createBrowserLifecycle from './createBrowserLifecycle.js';
|
|
21
|
+
import guardJourneyOrigin from './guardJourneyOrigin.js';
|
|
22
|
+
import isPageReady from './isPageReady.js';
|
|
23
|
+
import launchBrowser from './launchBrowser.js';
|
|
21
24
|
import { HEADLESS_USER_COOKIE } from '../server/auth/headlessUser.js';
|
|
22
25
|
import resolveHeadlessUser from '../server/auth/resolveHeadlessUser.js';
|
|
26
|
+
import { JOURNEY_COOKIES, writeJourneyCookie } from '../server/journeyCookies.js';
|
|
27
|
+
import recordingCookiePayload from '../server/recording/recordingCookiePayload.js';
|
|
23
28
|
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} catch {
|
|
32
|
-
return await chromium.launch();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Module-level singleton — a browser process is expensive to start, so it is
|
|
37
|
-
// launched once and reused across every headless caller (screenshots, state
|
|
38
|
-
// inspection, operator evaluation). Cached as a promise so concurrent calls
|
|
39
|
-
// awaiting startup share the same launch instead of racing.
|
|
40
|
-
let browserPromise = null;
|
|
41
|
-
|
|
42
|
-
async function getBrowser() {
|
|
43
|
-
if (type.isNone(browserPromise)) {
|
|
44
|
-
// Clear the cache on failure so the next call retries the launch
|
|
45
|
-
// instead of replaying a cached rejection forever.
|
|
46
|
-
browserPromise = launchBrowser().catch((error) => {
|
|
47
|
-
browserPromise = null;
|
|
48
|
-
throw error;
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
let browser = await browserPromise;
|
|
52
|
-
if (!browser.isConnected()) {
|
|
53
|
-
browserPromise = launchBrowser().catch((error) => {
|
|
54
|
-
browserPromise = null;
|
|
55
|
-
throw error;
|
|
56
|
-
});
|
|
57
|
-
browser = await browserPromise;
|
|
58
|
-
}
|
|
59
|
-
return browser;
|
|
60
|
-
}
|
|
29
|
+
// Module-level singleton, shared by every headless caller (screenshots,
|
|
30
|
+
// journeys, state inspection, operator evaluation, state loads) and closed
|
|
31
|
+
// after 90 s unused. See createBrowserLifecycle.js.
|
|
32
|
+
const { getBrowser, trackContext } = createBrowserLifecycle({
|
|
33
|
+
launch: launchBrowser,
|
|
34
|
+
idleTimeout: 90_000,
|
|
35
|
+
});
|
|
61
36
|
|
|
62
37
|
// `origin` should already include any configured basePath prefix that the
|
|
63
38
|
// caller can't derive itself (e.g. from a request URL) — here it's read from
|
|
64
39
|
// build/config.json (the same source app.js uses to mount the app) so
|
|
65
|
-
// callers only need to pass the bare origin.
|
|
66
|
-
|
|
40
|
+
// callers only need to pass the bare origin. `urlQuery` (an object) is
|
|
41
|
+
// appended as a query string, serialized by the same helper the engine uses
|
|
42
|
+
// for Link urlQuery, so a page reads it back through _url_query unchanged.
|
|
43
|
+
// `path` is the page's path pattern (readPagePath), filled with `pathParams`
|
|
44
|
+
// by the builder links use; it throws when a placeholder has no value.
|
|
45
|
+
function buildPageUrl({ origin, pageId, path, pathParams, urlQuery }) {
|
|
67
46
|
const basePath = lowdefyConfig.basePath ?? '';
|
|
68
|
-
|
|
47
|
+
const url = `${origin}${basePath}/${buildPagePath({ pageId, path, pathParams })}`;
|
|
48
|
+
const query = urlQueryFn.stringify(urlQuery);
|
|
49
|
+
if (query === '') {
|
|
50
|
+
return url;
|
|
51
|
+
}
|
|
52
|
+
return `${url}?${query}`;
|
|
69
53
|
}
|
|
70
54
|
|
|
71
55
|
// Opens a fresh browser context + page at the app's pageId route. Callers
|
|
@@ -76,52 +60,138 @@ async function openPage({
|
|
|
76
60
|
browser,
|
|
77
61
|
origin,
|
|
78
62
|
pageId,
|
|
63
|
+
path,
|
|
64
|
+
pathParams,
|
|
79
65
|
user,
|
|
66
|
+
urlQuery,
|
|
80
67
|
width = 1280,
|
|
81
68
|
height = 800,
|
|
69
|
+
colorScheme = 'light',
|
|
70
|
+
clientAddress,
|
|
71
|
+
dataCookie,
|
|
72
|
+
mutantCookie,
|
|
73
|
+
recording,
|
|
74
|
+
onContext,
|
|
82
75
|
timeout = 15000,
|
|
83
76
|
}) {
|
|
84
|
-
const url = buildPageUrl({ origin, pageId });
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
await
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
77
|
+
const url = buildPageUrl({ origin, pageId, path, pathParams, urlQuery });
|
|
78
|
+
// `none` injects no caller: the context starts signed out and the app's own
|
|
79
|
+
// auth resolves every request from the session cookies it sets. Otherwise
|
|
80
|
+
// the user is resolved before the context is created so an invalid `user`
|
|
81
|
+
// can't leave an orphaned context behind.
|
|
82
|
+
const injectedUser = user === 'none' ? null : resolveHeadlessUser({ user });
|
|
83
|
+
// colorScheme is what the page's `prefers-color-scheme` media query reports,
|
|
84
|
+
// so an app following the system theme renders light or dark accordingly.
|
|
85
|
+
const context = await browser.newContext({ viewport: { width, height }, colorScheme });
|
|
86
|
+
trackContext(context);
|
|
87
|
+
// The URLs a data set journey's context tried to reach on another host of the dev server. Each
|
|
88
|
+
// was aborted; the journey runner fails the step that caused it.
|
|
89
|
+
const leftOrigin = [];
|
|
90
|
+
// From here a failure must close the context before rethrowing: callers only
|
|
91
|
+
// learn about the context from the return value, so an error thrown mid-open
|
|
92
|
+
// (a navigation that times out, a crashed page) would otherwise
|
|
93
|
+
// leak a browser context — and its renderer process — on every failed call.
|
|
100
94
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
// A caller that watches the context (a journey's network counter) hooks in
|
|
96
|
+
// here, before the first request leaves.
|
|
97
|
+
if (!type.isUndefined(onContext)) {
|
|
98
|
+
await onContext(context);
|
|
99
|
+
}
|
|
100
|
+
// Inject an authenticated user so auth-protected pages don't 404 for the
|
|
101
|
+
// cookieless headless context. Mirrors the e2e user-cookie pattern; scoped to
|
|
102
|
+
// `origin` so it rides along on the same-origin /api/* fetches. A user the
|
|
103
|
+
// caller named is explicit: it beats a dev mock user (createLowdefyContext),
|
|
104
|
+
// while the roleless default does not, so a screenshot under a mock user
|
|
105
|
+
// still sees what the developer sees.
|
|
106
|
+
if (injectedUser !== null) {
|
|
107
|
+
const caller = { user: injectedUser, explicit: !type.isNone(user) };
|
|
108
|
+
await context.addCookies([
|
|
109
|
+
{
|
|
110
|
+
name: HEADLESS_USER_COOKIE,
|
|
111
|
+
value: Buffer.from(JSON.stringify(caller)).toString('base64'),
|
|
112
|
+
url: origin,
|
|
113
|
+
},
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
// clientAddress is the address the context's requests come from, as far
|
|
117
|
+
// as the dev server's auth rate limits can tell - see createJourneyActors
|
|
118
|
+
// and journeyActor.js. A cookie, not a header, so it only reaches the app;
|
|
119
|
+
// httpOnly, so page JavaScript cannot read the token. Lax, not Strict: a
|
|
120
|
+
// journey opens an emailed link from a data: URL, a cross-site navigation
|
|
121
|
+
// that a Strict cookie does not ride, and that one verify request would
|
|
122
|
+
// then fall back to the shared loopback address (magic-link verify allows
|
|
123
|
+
// 5 per minute per address).
|
|
124
|
+
if (!type.isUndefined(clientAddress)) {
|
|
125
|
+
await context.addCookies([
|
|
126
|
+
writeJourneyCookie({ name: JOURNEY_COOKIES.actor.name, payload: clientAddress, origin }),
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
// A journey on a data set: every request from this context reads the data
|
|
130
|
+
// session's database (see lib/server/applyDataSetRedirect.js), while the
|
|
131
|
+
// developer's own tabs keep the app's real one. Set before the first
|
|
132
|
+
// navigation, so no request from this context ever goes without it.
|
|
133
|
+
if (!type.isUndefined(dataCookie)) {
|
|
134
|
+
await context.addCookies([
|
|
135
|
+
writeJourneyCookie({ name: JOURNEY_COOKIES.data.name, payload: dataCookie, origin }),
|
|
136
|
+
]);
|
|
137
|
+
await guardJourneyOrigin({
|
|
138
|
+
context,
|
|
139
|
+
origin,
|
|
140
|
+
onLeave: (departure) => leftOrigin.push(departure),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// A harden run's mutant: every request from this context reads the mutated
|
|
144
|
+
// artifact (see lib/server/mutants), while other contexts do not.
|
|
145
|
+
if (!type.isUndefined(mutantCookie)) {
|
|
146
|
+
await context.addCookies([
|
|
147
|
+
writeJourneyCookie({ name: JOURNEY_COOKIES.mutant.name, payload: mutantCookie, origin }),
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
// Every headless context is marked for the dev recorder: 'off' unless the
|
|
151
|
+
// caller records a journey run, so screenshots and inspection
|
|
152
|
+
// never record, and a run's records are labelled by the server, not the
|
|
153
|
+
// page. See lib/server/recording.
|
|
154
|
+
await context.addCookies([
|
|
155
|
+
writeJourneyCookie({
|
|
156
|
+
name: JOURNEY_COOKIES.recording.name,
|
|
157
|
+
payload: recordingCookiePayload({ recording }),
|
|
158
|
+
origin,
|
|
159
|
+
}),
|
|
160
|
+
]);
|
|
161
|
+
const page = await context.newPage();
|
|
162
|
+
// 'load', not 'networkidle': every dev page holds the /api/reload event
|
|
163
|
+
// stream open, so the network never goes idle and a networkidle wait
|
|
164
|
+
// always ran to its full timeout before anything else happened.
|
|
105
165
|
await page.goto(url, { waitUntil: 'load', timeout });
|
|
166
|
+
// The engine builds the page context (and runs onInit + initial requests)
|
|
167
|
+
// after the bundle loads — 'load' fires before that. Every caller
|
|
168
|
+
// (screenshot, inspect, eval, checkpoint load, journeys) needs the app's
|
|
169
|
+
// async lifecycle to have settled, not just the bundle to have loaded, so
|
|
170
|
+
// wait on isPageReady - for the instance the app shows, which is not the
|
|
171
|
+
// one asked for when the app redirects, as a protected page does for a
|
|
172
|
+
// signed-out caller. Tolerant: on timeout proceed with ready:
|
|
173
|
+
// false and let the caller surface what it finds — a snapshot of a hung
|
|
174
|
+
// page is still useful signal, and a far better answer than a tool failure.
|
|
175
|
+
let ready = true;
|
|
176
|
+
await page.waitForFunction(isPageReady, undefined, { timeout }).catch(() => {
|
|
177
|
+
ready = false;
|
|
178
|
+
});
|
|
179
|
+
// Images blocks render start loading only once the page is ready; a
|
|
180
|
+
// screenshot taken before they arrive shows empty frames. A lazy image
|
|
181
|
+
// below the fold never loads until scrolled to, so it counts as done.
|
|
182
|
+
await page
|
|
183
|
+
.waitForFunction(
|
|
184
|
+
() =>
|
|
185
|
+
Array.from(document.images).every((image) => image.complete || image.loading === 'lazy'),
|
|
186
|
+
undefined,
|
|
187
|
+
{ timeout }
|
|
188
|
+
)
|
|
189
|
+
.catch(() => {});
|
|
190
|
+
return { context, page, ready, url, leftOrigin };
|
|
191
|
+
} catch (error) {
|
|
192
|
+
await context.close().catch(() => {});
|
|
193
|
+
throw error;
|
|
106
194
|
}
|
|
107
|
-
// The engine builds the page context (and runs onInit + initial requests)
|
|
108
|
-
// after the bundle loads — 'load'/'networkidle' fire before that. Every
|
|
109
|
-
// caller (screenshot, inspect, eval, checkpoint load) needs the app
|
|
110
|
-
// actually mounted, so wait for the context and for initial requests to
|
|
111
|
-
// settle. Tolerant: on timeout proceed and let the caller surface what it
|
|
112
|
-
// finds — a screenshot of a hung page is still useful signal.
|
|
113
|
-
await page
|
|
114
|
-
.waitForFunction(
|
|
115
|
-
(id) => {
|
|
116
|
-
const pageContext = window.lowdefy?.contexts?.[`page:${id}`];
|
|
117
|
-
if (!pageContext) return false;
|
|
118
|
-
return !Object.values(pageContext.requests ?? {}).some((calls) => calls?.[0]?.loading);
|
|
119
|
-
},
|
|
120
|
-
pageId,
|
|
121
|
-
{ timeout }
|
|
122
|
-
)
|
|
123
|
-
.catch(() => {});
|
|
124
|
-
return { context, page, url };
|
|
125
195
|
}
|
|
126
196
|
|
|
127
197
|
export { getBrowser, openPage, buildPageUrl };
|