@lowdefy/server-dev 6.0.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 +63 -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 +224 -39
- 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/getAuth.js +46 -0
- 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/{getAuthConfig.js → getStrategies.js} +12 -10
- 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 +174 -41
- package/lib/server/createLowdefyContext.test.mjs +437 -0
- 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 +77 -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/scrubSecrets.js +23 -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 +61 -49
- package/package.original.json +61 -49
- 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 +196 -14
- 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 +4 -2
- 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/lib/server/auth/session.js +0 -39
- 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
|
@@ -21,6 +21,7 @@ const mockSerializeBuildException = jest.fn((exception) => ({ message: exception
|
|
|
21
21
|
const mockWriteBuildStatus = jest.fn();
|
|
22
22
|
const mockCreateCustomPluginTypesMap = jest.fn().mockResolvedValue({});
|
|
23
23
|
const mockCreateCustomPluginMessagesMap = jest.fn().mockResolvedValue({});
|
|
24
|
+
const mockPublishBuildDirectory = jest.fn(async () => {});
|
|
24
25
|
|
|
25
26
|
jest.unstable_mockModule('@lowdefy/build/dev', () => ({
|
|
26
27
|
shallowBuild: mockShallowBuild,
|
|
@@ -35,12 +36,15 @@ jest.unstable_mockModule('../utils/createCustomPluginTypesMap.mjs', () => ({
|
|
|
35
36
|
jest.unstable_mockModule('../utils/createCustomPluginMessagesMap.mjs', () => ({
|
|
36
37
|
default: mockCreateCustomPluginMessagesMap,
|
|
37
38
|
}));
|
|
39
|
+
jest.unstable_mockModule('../utils/publishBuildDirectory.mjs', () => ({
|
|
40
|
+
default: mockPublishBuildDirectory,
|
|
41
|
+
}));
|
|
38
42
|
|
|
39
43
|
const { default: lowdefyBuild } = await import('./lowdefyBuild.mjs');
|
|
40
44
|
|
|
41
45
|
function createContext() {
|
|
42
46
|
return {
|
|
43
|
-
directories: { build: '/app/build' },
|
|
47
|
+
directories: { build: '/app/build', buildStaging: '/app/build-staging' },
|
|
44
48
|
logger: { info: jest.fn() },
|
|
45
49
|
options: { refResolver: undefined },
|
|
46
50
|
};
|
|
@@ -100,3 +104,134 @@ test('lowdefyBuild falls back to the raw error message when the thrown error has
|
|
|
100
104
|
warnings: [],
|
|
101
105
|
});
|
|
102
106
|
});
|
|
107
|
+
|
|
108
|
+
test('lowdefyBuild writes an error buildStatus.json when lowdefy.yaml cannot be read for its plugins', async () => {
|
|
109
|
+
const context = createContext();
|
|
110
|
+
const parseError = new Error('All sequence items must start at the same column at line 7');
|
|
111
|
+
mockCreateCustomPluginTypesMap.mockRejectedValueOnce(parseError);
|
|
112
|
+
|
|
113
|
+
const build = lowdefyBuild(context);
|
|
114
|
+
await expect(build()).rejects.toBe(parseError);
|
|
115
|
+
|
|
116
|
+
expect(mockShallowBuild).not.toHaveBeenCalled();
|
|
117
|
+
expect(mockWriteBuildStatus).toHaveBeenCalledWith({
|
|
118
|
+
directories: context.directories,
|
|
119
|
+
status: 'error',
|
|
120
|
+
errors: [{ message: 'All sequence items must start at the same column at line 7' }],
|
|
121
|
+
warnings: [],
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('lowdefyBuild builds into the staging directory and then publishes it', async () => {
|
|
126
|
+
const context = createContext();
|
|
127
|
+
mockShallowBuild.mockResolvedValue({ components: {}, pageRegistry: {}, context: {} });
|
|
128
|
+
|
|
129
|
+
const build = lowdefyBuild(context);
|
|
130
|
+
await build();
|
|
131
|
+
|
|
132
|
+
expect(mockShallowBuild.mock.calls[0][0].directories).toEqual({
|
|
133
|
+
build: '/app/build-staging',
|
|
134
|
+
buildStaging: '/app/build-staging',
|
|
135
|
+
});
|
|
136
|
+
expect(mockPublishBuildDirectory).toHaveBeenCalledWith({
|
|
137
|
+
buildDirectory: '/app/build',
|
|
138
|
+
stagingDirectory: '/app/build-staging',
|
|
139
|
+
});
|
|
140
|
+
expect(mockPublishBuildDirectory.mock.invocationCallOrder[0]).toBeLessThan(
|
|
141
|
+
mockWriteBuildStatus.mock.invocationCallOrder[0]
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('lowdefyBuild leaves the live build in place when the build fails', async () => {
|
|
146
|
+
const context = createContext();
|
|
147
|
+
mockShallowBuild.mockRejectedValue(new Error('Build failed'));
|
|
148
|
+
|
|
149
|
+
const build = lowdefyBuild(context);
|
|
150
|
+
await expect(build()).rejects.toThrow('Build failed');
|
|
151
|
+
|
|
152
|
+
expect(mockPublishBuildDirectory).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('lowdefyBuild writes an error buildStatus.json and rethrows when publishing the build fails', async () => {
|
|
156
|
+
const context = createContext();
|
|
157
|
+
mockShallowBuild.mockResolvedValue({ components: {}, pageRegistry: {}, context: {} });
|
|
158
|
+
const renameError = new Error("EPERM: operation not permitted, rename 'a' -> 'b'");
|
|
159
|
+
mockPublishBuildDirectory.mockRejectedValueOnce(renameError);
|
|
160
|
+
|
|
161
|
+
const build = lowdefyBuild(context);
|
|
162
|
+
await expect(build()).rejects.toThrow(
|
|
163
|
+
"Publishing the build to /app/build failed: EPERM: operation not permitted, rename 'a' -> 'b'"
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(mockWriteBuildStatus).toHaveBeenCalledTimes(1);
|
|
167
|
+
expect(mockWriteBuildStatus).toHaveBeenCalledWith({
|
|
168
|
+
directories: context.directories,
|
|
169
|
+
status: 'error',
|
|
170
|
+
errors: [
|
|
171
|
+
{
|
|
172
|
+
message:
|
|
173
|
+
"Publishing the build to /app/build failed: EPERM: operation not permitted, rename 'a' -> 'b'",
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
warnings: [],
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('lowdefyBuild starts a build only after the previous one has finished', async () => {
|
|
181
|
+
const context = createContext();
|
|
182
|
+
const events = [];
|
|
183
|
+
let finishFirst;
|
|
184
|
+
mockShallowBuild
|
|
185
|
+
.mockImplementationOnce(() => {
|
|
186
|
+
events.push('first start');
|
|
187
|
+
return new Promise((resolve) => {
|
|
188
|
+
finishFirst = () => {
|
|
189
|
+
events.push('first end');
|
|
190
|
+
resolve({ components: {}, pageRegistry: {}, context: {} });
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
})
|
|
194
|
+
.mockImplementationOnce(async () => {
|
|
195
|
+
events.push('second start');
|
|
196
|
+
return { components: {}, pageRegistry: {}, context: {} };
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const build = lowdefyBuild(context);
|
|
200
|
+
const first = build();
|
|
201
|
+
const second = build();
|
|
202
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
203
|
+
expect(events).toEqual(['first start']);
|
|
204
|
+
finishFirst();
|
|
205
|
+
await Promise.all([first, second]);
|
|
206
|
+
|
|
207
|
+
expect(events).toEqual(['first start', 'first end', 'second start']);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test('lowdefyBuild runs the next build after a failed one', async () => {
|
|
211
|
+
const context = createContext();
|
|
212
|
+
mockShallowBuild
|
|
213
|
+
.mockRejectedValueOnce(new Error('Build failed'))
|
|
214
|
+
.mockResolvedValueOnce({ components: {}, pageRegistry: {}, context: {} });
|
|
215
|
+
|
|
216
|
+
const build = lowdefyBuild(context);
|
|
217
|
+
const first = build();
|
|
218
|
+
const second = build();
|
|
219
|
+
|
|
220
|
+
await expect(first).rejects.toThrow('Build failed');
|
|
221
|
+
await expect(second).resolves.toEqual({ components: {}, pageRegistry: {}, context: {} });
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('lowdefyBuild reads the plugin types and messages maps in parallel', async () => {
|
|
225
|
+
const context = createContext();
|
|
226
|
+
let releaseTypes;
|
|
227
|
+
mockCreateCustomPluginTypesMap.mockImplementationOnce(
|
|
228
|
+
() => new Promise((resolve) => (releaseTypes = () => resolve({})))
|
|
229
|
+
);
|
|
230
|
+
mockShallowBuild.mockResolvedValue({ components: {}, pageRegistry: {}, context: {} });
|
|
231
|
+
|
|
232
|
+
const build = lowdefyBuild(context)();
|
|
233
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
234
|
+
expect(mockCreateCustomPluginMessagesMap).toHaveBeenCalledTimes(1);
|
|
235
|
+
releaseTypes();
|
|
236
|
+
await build;
|
|
237
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { spawnProcess } from '@lowdefy/node-utils';
|
|
18
|
+
|
|
19
|
+
import createServerEnv from '../utils/createServerEnv.mjs';
|
|
20
|
+
|
|
21
|
+
// Runs Vite's dependency optimiser in a short-lived process before the Vite
|
|
22
|
+
// child starts, so the long-lived child starts against a warm
|
|
23
|
+
// node_modules/.vite/deps cache and never optimises itself. Rolldown keeps
|
|
24
|
+
// 500-600 MB of native memory after optimising, and only ending the process
|
|
25
|
+
// gives it back. With a valid cache this returns after resolving the config.
|
|
26
|
+
// Runs after a build: vite.config.js reads build/config.json when it loads.
|
|
27
|
+
function optimizeDependencies(context) {
|
|
28
|
+
return async () => {
|
|
29
|
+
const started = Date.now();
|
|
30
|
+
context.logger.debug('Optimizing dependencies...');
|
|
31
|
+
const stderr = [];
|
|
32
|
+
try {
|
|
33
|
+
await spawnProcess({
|
|
34
|
+
command: 'node',
|
|
35
|
+
args: [context.bin.vite, 'optimize'],
|
|
36
|
+
processOptions: {
|
|
37
|
+
cwd: context.directories.server,
|
|
38
|
+
env: createServerEnv(context),
|
|
39
|
+
},
|
|
40
|
+
stdOutLineHandler: (line) => context.logger.debug(line),
|
|
41
|
+
stdErrLineHandler: (line) => {
|
|
42
|
+
stderr.push(String(line));
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
} catch (error) {
|
|
46
|
+
// Never stops the server from starting: the child then optimises
|
|
47
|
+
// itself, as it did before this step existed.
|
|
48
|
+
context.logger.warn(
|
|
49
|
+
`Dependency optimization failed (${
|
|
50
|
+
error.message
|
|
51
|
+
}); the dev server optimizes on start instead.\n${stderr.slice(-20).join('\n')}`
|
|
52
|
+
);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
context.logger.debug(`Optimized dependencies in ${Date.now() - started} ms.`);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export default optimizeDependencies;
|
|
@@ -15,14 +15,42 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import startServer from './startServer.mjs';
|
|
18
|
+
import waitForChildExit from '../utils/waitForChildExit.mjs';
|
|
19
|
+
import waitForDevServer from './waitForDevServer.mjs';
|
|
18
20
|
|
|
21
|
+
// Resolves once the new server answers, and counts as build activity until
|
|
22
|
+
// then, so lowdefy_build_status({ wait: true }) waits through a restart
|
|
23
|
+
// instead of answering before it and leaving the next call to hit it.
|
|
19
24
|
function restartServer(context) {
|
|
20
|
-
return () =>
|
|
21
|
-
context.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
return () =>
|
|
26
|
+
context.buildActivity.track(async () => {
|
|
27
|
+
context.shutdownServer();
|
|
28
|
+
context.logger.info({ spin: 'start' }, 'Restarting server...');
|
|
29
|
+
// The new child binds the internal port with --strictPort, so it fails
|
|
30
|
+
// with "Port in use" if the old child is still exiting. A caller that
|
|
31
|
+
// shut the server down earlier (syncServer's install path) is covered
|
|
32
|
+
// too: the stopped child is kept until a restart has waited for it.
|
|
33
|
+
const stoppedChild = context.stoppedDevServer;
|
|
34
|
+
const exited = await waitForChildExit({ child: stoppedChild });
|
|
35
|
+
if (context.stoppedDevServer === stoppedChild) {
|
|
36
|
+
context.stoppedDevServer = null;
|
|
37
|
+
}
|
|
38
|
+
if (!exited) {
|
|
39
|
+
context.logger.warn(
|
|
40
|
+
`The old dev server (pid ${stoppedChild.pid}) did not exit after SIGKILL; starting the new one anyway.`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
// What this server reads at start, so a later build restarts it only
|
|
44
|
+
// when one of those files changed.
|
|
45
|
+
context.serverArtifacts.record();
|
|
46
|
+
startServer(context);
|
|
47
|
+
const ready = await waitForDevServer(context);
|
|
48
|
+
if (ready) {
|
|
49
|
+
context.logger.info({ spin: 'succeed' }, 'Restarted server.');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
context.logger.warn('The restarted dev server did not answer - check the output above.');
|
|
53
|
+
});
|
|
26
54
|
}
|
|
27
55
|
|
|
28
56
|
export default restartServer;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { EventEmitter } from 'node:events';
|
|
18
|
+
|
|
19
|
+
import { jest } from '@jest/globals';
|
|
20
|
+
|
|
21
|
+
const events = [];
|
|
22
|
+
|
|
23
|
+
jest.unstable_mockModule('./startServer.mjs', () => ({
|
|
24
|
+
default: jest.fn((context) => {
|
|
25
|
+
events.push('start');
|
|
26
|
+
context.devServer = createChild();
|
|
27
|
+
}),
|
|
28
|
+
}));
|
|
29
|
+
jest.unstable_mockModule('../utils/waitForServer.mjs', () => ({
|
|
30
|
+
default: jest.fn(async () => true),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
function createChild() {
|
|
34
|
+
return Object.assign(new EventEmitter(), {
|
|
35
|
+
exitCode: null,
|
|
36
|
+
signalCode: null,
|
|
37
|
+
killed: false,
|
|
38
|
+
pid: 1234,
|
|
39
|
+
kill: jest.fn(),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function createContext({ devServer = null } = {}) {
|
|
44
|
+
const { default: shutdownServer } = await import('./shutdownServer.mjs');
|
|
45
|
+
const context = {
|
|
46
|
+
buildActivity: { track: (fn) => fn() },
|
|
47
|
+
devServer,
|
|
48
|
+
logger: { debug: jest.fn(), info: jest.fn(), warn: jest.fn() },
|
|
49
|
+
markServerReady: jest.fn(),
|
|
50
|
+
serverArtifacts: { record: jest.fn() },
|
|
51
|
+
};
|
|
52
|
+
context.shutdownServer = shutdownServer(context);
|
|
53
|
+
return context;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
events.length = 0;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
jest.useRealTimers();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
async function flush() {
|
|
65
|
+
for (let i = 0; i < 10; i += 1) {
|
|
66
|
+
await Promise.resolve();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function advance(ms) {
|
|
71
|
+
await flush();
|
|
72
|
+
jest.advanceTimersByTime(ms);
|
|
73
|
+
await flush();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
test('restartServer starts the new child only after the old child exits', async () => {
|
|
77
|
+
const { default: restartServer } = await import('./restartServer.mjs');
|
|
78
|
+
const oldChild = createChild();
|
|
79
|
+
const context = await createContext({ devServer: oldChild });
|
|
80
|
+
|
|
81
|
+
const restarting = restartServer(context)();
|
|
82
|
+
await flush();
|
|
83
|
+
expect(oldChild.kill).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(events).toEqual([]);
|
|
85
|
+
|
|
86
|
+
oldChild.signalCode = 'SIGTERM';
|
|
87
|
+
oldChild.emit('exit', null, 'SIGTERM');
|
|
88
|
+
await restarting;
|
|
89
|
+
|
|
90
|
+
expect(events).toEqual(['start']);
|
|
91
|
+
expect(context.devServer).not.toBe(oldChild);
|
|
92
|
+
expect(context.stoppedDevServer).toBe(null);
|
|
93
|
+
expect(context.logger.warn).not.toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('restartServer SIGKILLs an old child that ignores SIGTERM, then starts the new child', async () => {
|
|
97
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
98
|
+
const { default: restartServer } = await import('./restartServer.mjs');
|
|
99
|
+
const oldChild = createChild();
|
|
100
|
+
oldChild.kill.mockImplementation((signal) => {
|
|
101
|
+
if (signal === 'SIGKILL') {
|
|
102
|
+
oldChild.signalCode = 'SIGKILL';
|
|
103
|
+
oldChild.emit('exit', null, 'SIGKILL');
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const context = await createContext({ devServer: oldChild });
|
|
107
|
+
|
|
108
|
+
const restarting = restartServer(context)();
|
|
109
|
+
await flush();
|
|
110
|
+
expect(events).toEqual([]);
|
|
111
|
+
await advance(10000);
|
|
112
|
+
await restarting;
|
|
113
|
+
|
|
114
|
+
expect(oldChild.kill).toHaveBeenCalledWith('SIGKILL');
|
|
115
|
+
expect(events).toEqual(['start']);
|
|
116
|
+
expect(context.logger.warn).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('restartServer finishes after both timeouts and warns when the old child never exits', async () => {
|
|
120
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
121
|
+
const { default: restartServer } = await import('./restartServer.mjs');
|
|
122
|
+
const oldChild = createChild();
|
|
123
|
+
const context = await createContext({ devServer: oldChild });
|
|
124
|
+
|
|
125
|
+
const restarting = restartServer(context)();
|
|
126
|
+
await advance(10000);
|
|
127
|
+
expect(events).toEqual([]);
|
|
128
|
+
await advance(5000);
|
|
129
|
+
await restarting;
|
|
130
|
+
|
|
131
|
+
expect(oldChild.kill).toHaveBeenCalledWith('SIGKILL');
|
|
132
|
+
expect(events).toEqual(['start']);
|
|
133
|
+
expect(context.logger.warn).toHaveBeenCalledWith(expect.stringContaining('did not exit'));
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('restartServer waits for a child that syncServer shut down before installing', async () => {
|
|
137
|
+
const { default: restartServer } = await import('./restartServer.mjs');
|
|
138
|
+
const oldChild = createChild();
|
|
139
|
+
const context = await createContext({ devServer: oldChild });
|
|
140
|
+
context.shutdownServer();
|
|
141
|
+
expect(context.devServer).toBe(null);
|
|
142
|
+
|
|
143
|
+
const restarting = restartServer(context)();
|
|
144
|
+
await flush();
|
|
145
|
+
expect(events).toEqual([]);
|
|
146
|
+
oldChild.exitCode = 0;
|
|
147
|
+
oldChild.emit('exit', 0, null);
|
|
148
|
+
await restarting;
|
|
149
|
+
|
|
150
|
+
expect(events).toEqual(['start']);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('restartServer with no previous child starts at once', async () => {
|
|
154
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
155
|
+
const { default: restartServer } = await import('./restartServer.mjs');
|
|
156
|
+
const context = await createContext();
|
|
157
|
+
|
|
158
|
+
await restartServer(context)();
|
|
159
|
+
|
|
160
|
+
expect(events).toEqual(['start']);
|
|
161
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
162
|
+
});
|
|
@@ -20,6 +20,17 @@ function shutdownServer(context) {
|
|
|
20
20
|
context.logger.debug(
|
|
21
21
|
`Existing dev server with pid ${context.devServer.pid}, killed: ${context.devServer.killed}`
|
|
22
22
|
);
|
|
23
|
+
const child = context.devServer;
|
|
24
|
+
// A signalled child keeps answering on the internal port until it
|
|
25
|
+
// exits; the proxy waits for this before probing for its replacement,
|
|
26
|
+
// or the probe would reach the old child and confirm the new one.
|
|
27
|
+
context.devServerExited =
|
|
28
|
+
child.exitCode !== null || child.signalCode !== null
|
|
29
|
+
? Promise.resolve()
|
|
30
|
+
: new Promise((resolve) => child.once('exit', resolve));
|
|
31
|
+
// Kept so a restart can wait for this child to free the internal port,
|
|
32
|
+
// and SIGKILL it if it does not.
|
|
33
|
+
context.stoppedDevServer = child;
|
|
23
34
|
if (!context.devServer.killed) {
|
|
24
35
|
context.logger.info({ spin: 'start' }, 'Shutting down server...');
|
|
25
36
|
context.devServer.kill();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { EventEmitter } from 'node:events';
|
|
18
|
+
|
|
19
|
+
import { jest } from '@jest/globals';
|
|
20
|
+
|
|
21
|
+
import shutdownServer from './shutdownServer.mjs';
|
|
22
|
+
|
|
23
|
+
test('shutdownServer records when the stopped child has exited, for the proxy to wait on', async () => {
|
|
24
|
+
const child = Object.assign(new EventEmitter(), {
|
|
25
|
+
exitCode: null,
|
|
26
|
+
signalCode: null,
|
|
27
|
+
killed: false,
|
|
28
|
+
kill: jest.fn(),
|
|
29
|
+
});
|
|
30
|
+
const context = { devServer: child, logger: { debug: jest.fn(), info: jest.fn() } };
|
|
31
|
+
|
|
32
|
+
shutdownServer(context)();
|
|
33
|
+
|
|
34
|
+
expect(child.kill).toHaveBeenCalledTimes(1);
|
|
35
|
+
expect(context.devServer).toBe(null);
|
|
36
|
+
let exited = false;
|
|
37
|
+
context.devServerExited.then(() => {
|
|
38
|
+
exited = true;
|
|
39
|
+
});
|
|
40
|
+
await Promise.resolve();
|
|
41
|
+
expect(exited).toBe(false);
|
|
42
|
+
child.emit('exit', null, 'SIGTERM');
|
|
43
|
+
await context.devServerExited;
|
|
44
|
+
expect(exited).toBe(true);
|
|
45
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import startServer from './startServer.mjs';
|
|
18
|
+
import waitForDevServer from './waitForDevServer.mjs';
|
|
19
|
+
|
|
20
|
+
// The manager's first child start: dependencies are optimised in a
|
|
21
|
+
// short-lived process first, so the child never runs the optimiser itself
|
|
22
|
+
// (see optimizeDependencies.mjs). It runs at the head of syncServer's queue,
|
|
23
|
+
// so a watcher batch during the optimise (a late file event from the initial
|
|
24
|
+
// build, an edit) builds at once and syncs after this start, instead of
|
|
25
|
+
// restarting a child that does not exist yet.
|
|
26
|
+
//
|
|
27
|
+
// The server artifacts are recorded before the optimise, not when the child
|
|
28
|
+
// spawns: a build during the optimise that adds a plugin package to
|
|
29
|
+
// package.json must still read as an install for the queued sync. An
|
|
30
|
+
// artifact that changed in that window costs one extra restart at most.
|
|
31
|
+
//
|
|
32
|
+
// The wait for the child to answer is part of the start, as it is in
|
|
33
|
+
// restartServer: a queued sync that restarted the child before it answered
|
|
34
|
+
// would end the wait on the killed child, and the manager would never record
|
|
35
|
+
// the server as ready. Resolves with whether the child answered within the
|
|
36
|
+
// wait; waitForDevServer marks the server ready, also on a later answer.
|
|
37
|
+
function startFirstServer(context) {
|
|
38
|
+
return context.syncServer.startFirst(async () => {
|
|
39
|
+
context.serverArtifacts.record();
|
|
40
|
+
await context.optimizeDependencies();
|
|
41
|
+
startServer(context);
|
|
42
|
+
return waitForDevServer(context);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default startFirstServer;
|