@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
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
// The context.waitUntil of a data-session request: background work (scheduleBackground, the detached
|
|
18
|
+
// dispatch and the detached run) is added to the session's work set, so closing the session waits
|
|
19
|
+
// for it before it drops the database.
|
|
20
|
+
function trackSessionWork({ session }) {
|
|
21
|
+
return function waitUntil(promise) {
|
|
22
|
+
session.work.add(promise);
|
|
23
|
+
const remove = () => {
|
|
24
|
+
session.work.delete(promise);
|
|
25
|
+
};
|
|
26
|
+
promise.then(remove, remove);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default trackSessionWork;
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
function escapeRegExp(value) {
|
|
18
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// The paths Vite serves itself; every other request routes to the Hono app.
|
|
22
|
+
// @hono/vite-dev-server tests these against the raw request url, before Vite
|
|
23
|
+
// strips its `base`, and Vite serves every module under `base` - so with
|
|
24
|
+
// config.basePath the patterns must carry the prefix. Without it
|
|
25
|
+
// `<basePath>/@vite/client` and `<basePath>/client/main.jsx` fall through to
|
|
26
|
+
// the Hono page route and come back as the HTML shell.
|
|
27
|
+
function createDevServerExclude({ basePath }) {
|
|
28
|
+
const prefix = escapeRegExp(basePath);
|
|
29
|
+
return [
|
|
30
|
+
new RegExp(`^${prefix}/client/.+`),
|
|
31
|
+
new RegExp(`^${prefix}/lib/.+`),
|
|
32
|
+
new RegExp(`^${prefix}/build/.+`),
|
|
33
|
+
new RegExp(`^${prefix}/@.+$`),
|
|
34
|
+
new RegExp(`^${prefix}/node_modules/.*`),
|
|
35
|
+
/\?t=\d+$/,
|
|
36
|
+
/^\/favicon\.ico$/,
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default createDevServerExclude;
|
|
@@ -0,0 +1,79 @@
|
|
|
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 createDevServerExclude from './createDevServerExclude.js';
|
|
18
|
+
|
|
19
|
+
function isExcluded(exclude, url) {
|
|
20
|
+
return exclude.some((pattern) => pattern.test(url));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
test('createDevServerExclude leaves Vite module paths to Vite when there is no basePath', () => {
|
|
24
|
+
const exclude = createDevServerExclude({ basePath: '' });
|
|
25
|
+
|
|
26
|
+
expect(isExcluded(exclude, '/@vite/client')).toBe(true);
|
|
27
|
+
expect(isExcluded(exclude, '/@react-refresh')).toBe(true);
|
|
28
|
+
expect(isExcluded(exclude, '/client/main.jsx')).toBe(true);
|
|
29
|
+
expect(isExcluded(exclude, '/build/plugins/blocks.js')).toBe(true);
|
|
30
|
+
expect(isExcluded(exclude, '/lib/client/ErrorBar.jsx')).toBe(true);
|
|
31
|
+
expect(isExcluded(exclude, '/node_modules/.vite/deps/react.js?v=1')).toBe(true);
|
|
32
|
+
expect(isExcluded(exclude, '/client/App.jsx?t=1712345678')).toBe(true);
|
|
33
|
+
expect(isExcluded(exclude, '/favicon.ico')).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('createDevServerExclude routes page, api and docs paths to Hono when there is no basePath', () => {
|
|
37
|
+
const exclude = createDevServerExclude({ basePath: '' });
|
|
38
|
+
|
|
39
|
+
expect(isExcluded(exclude, '/')).toBe(false);
|
|
40
|
+
expect(isExcluded(exclude, '/home')).toBe(false);
|
|
41
|
+
expect(isExcluded(exclude, '/api/ping')).toBe(false);
|
|
42
|
+
expect(isExcluded(exclude, '/lowdefy-docs/mcp')).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('createDevServerExclude leaves Vite module paths under the basePath to Vite', () => {
|
|
46
|
+
const exclude = createDevServerExclude({ basePath: '/app' });
|
|
47
|
+
|
|
48
|
+
expect(isExcluded(exclude, '/app/@vite/client')).toBe(true);
|
|
49
|
+
expect(isExcluded(exclude, '/app/@react-refresh')).toBe(true);
|
|
50
|
+
expect(isExcluded(exclude, '/app/@fs/Users/dev/app/plugin.js')).toBe(true);
|
|
51
|
+
expect(isExcluded(exclude, '/app/client/main.jsx')).toBe(true);
|
|
52
|
+
expect(isExcluded(exclude, '/app/build/plugins/blocks.js')).toBe(true);
|
|
53
|
+
expect(isExcluded(exclude, '/app/lib/client/ErrorBar.jsx')).toBe(true);
|
|
54
|
+
expect(isExcluded(exclude, '/app/node_modules/.vite/deps/react.js?v=1')).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('createDevServerExclude routes page, api and docs paths under the basePath to Hono', () => {
|
|
58
|
+
const exclude = createDevServerExclude({ basePath: '/app' });
|
|
59
|
+
|
|
60
|
+
expect(isExcluded(exclude, '/app')).toBe(false);
|
|
61
|
+
expect(isExcluded(exclude, '/app/home')).toBe(false);
|
|
62
|
+
expect(isExcluded(exclude, '/app/client-list')).toBe(false);
|
|
63
|
+
expect(isExcluded(exclude, '/app/api/ping')).toBe(false);
|
|
64
|
+
expect(isExcluded(exclude, '/app/lowdefy-docs/mcp')).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('createDevServerExclude does not hand unprefixed module paths to Vite under a basePath', () => {
|
|
68
|
+
const exclude = createDevServerExclude({ basePath: '/app' });
|
|
69
|
+
|
|
70
|
+
expect(isExcluded(exclude, '/@vite/client')).toBe(false);
|
|
71
|
+
expect(isExcluded(exclude, '/client/main.jsx')).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('createDevServerExclude matches a basePath containing regular expression characters literally', () => {
|
|
75
|
+
const exclude = createDevServerExclude({ basePath: '/my.app' });
|
|
76
|
+
|
|
77
|
+
expect(isExcluded(exclude, '/my.app/@vite/client')).toBe(true);
|
|
78
|
+
expect(isExcluded(exclude, '/myxapp/@vite/client')).toBe(false);
|
|
79
|
+
});
|
package/manager/getContext.mjs
CHANGED
|
@@ -25,13 +25,17 @@ import checkMockUserWarning from './processes/checkMockUserWarning.mjs';
|
|
|
25
25
|
import initialBuild from './processes/initialBuild.mjs';
|
|
26
26
|
import installPlugins from './processes/installPlugins.mjs';
|
|
27
27
|
import lowdefyBuild from './processes/lowdefyBuild.mjs';
|
|
28
|
+
import optimizeDependencies from './processes/optimizeDependencies.mjs';
|
|
28
29
|
import readDotEnv from './processes/readDotEnv.mjs';
|
|
29
30
|
import reloadClients from './processes/reloadClients.mjs';
|
|
30
31
|
import restartServer from './processes/restartServer.mjs';
|
|
31
32
|
import shutdownServer from './processes/shutdownServer.mjs';
|
|
32
33
|
import startWatchers from './processes/startWatchers.mjs';
|
|
34
|
+
import syncServer from './processes/syncServer.mjs';
|
|
33
35
|
|
|
36
|
+
import createServerArtifactTracker from './utils/createServerArtifactTracker.mjs';
|
|
34
37
|
import getViteBin from './utils/getViteBin.mjs';
|
|
38
|
+
import readManagerVersion from './utils/readManagerVersion.mjs';
|
|
35
39
|
|
|
36
40
|
const argv = yargs(hideBin(process.argv)).array('watch').array('watchIgnore').argv;
|
|
37
41
|
|
|
@@ -44,6 +48,7 @@ async function getContext() {
|
|
|
44
48
|
},
|
|
45
49
|
directories: {
|
|
46
50
|
build: path.resolve(process.cwd(), './build'),
|
|
51
|
+
buildStaging: path.resolve(process.cwd(), './build-staging'),
|
|
47
52
|
config: path.resolve(argv.configDirectory ?? env.LOWDEFY_DIRECTORY_CONFIG ?? process.cwd()),
|
|
48
53
|
server: process.cwd(),
|
|
49
54
|
},
|
|
@@ -54,8 +59,14 @@ async function getContext() {
|
|
|
54
59
|
destination: pino.destination({ dest: 1, sync: true }),
|
|
55
60
|
}),
|
|
56
61
|
options: {
|
|
62
|
+
internalPort: env.LOWDEFY_SERVER_DEV_INTERNAL_PORT
|
|
63
|
+
? Number(env.LOWDEFY_SERVER_DEV_INTERNAL_PORT)
|
|
64
|
+
: undefined,
|
|
65
|
+
owner: env.LOWDEFY_DEV_OWNER === 'hub' ? 'hub' : 'terminal',
|
|
57
66
|
port: Number(argv.port ?? env.PORT ?? 3000),
|
|
58
67
|
refResolver: argv.refResolver ?? env.LOWDEFY_BUILD_REF_RESOLVER,
|
|
68
|
+
skipPluginChecks: env.LOWDEFY_BUILD_SKIP_PLUGIN_CHECKS === 'true',
|
|
69
|
+
strictPort: env.LOWDEFY_SERVER_DEV_STRICT_PORT === 'true',
|
|
59
70
|
watch:
|
|
60
71
|
argv.watch ?? env.LOWDEFY_SERVER_DEV_WATCH ? JSON.parse(env.LOWDEFY_SERVER_DEV_WATCH) : [],
|
|
61
72
|
watchIgnore:
|
|
@@ -63,11 +74,12 @@ async function getContext() {
|
|
|
63
74
|
? JSON.parse(env.LOWDEFY_SERVER_DEV_WATCH_IGNORE)
|
|
64
75
|
: [],
|
|
65
76
|
},
|
|
66
|
-
version:
|
|
77
|
+
version: readManagerVersion(),
|
|
67
78
|
|
|
68
79
|
// JIT build state
|
|
69
80
|
pageRegistry: null,
|
|
70
81
|
buildContext: null,
|
|
82
|
+
lastBuildFailed: false,
|
|
71
83
|
};
|
|
72
84
|
|
|
73
85
|
context.packageManagerCmd = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
|
|
@@ -78,18 +90,28 @@ async function getContext() {
|
|
|
78
90
|
// Wrap lowdefyBuild to capture and store the shallow build result
|
|
79
91
|
const buildFn = lowdefyBuild(context);
|
|
80
92
|
context.lowdefyBuild = async () => {
|
|
81
|
-
|
|
93
|
+
let result;
|
|
94
|
+
try {
|
|
95
|
+
result = await buildFn();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
context.lastBuildFailed = true;
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
context.lastBuildFailed = false;
|
|
82
101
|
if (result) {
|
|
83
102
|
context.pageRegistry = result.pageRegistry;
|
|
84
103
|
context.buildContext = result.context;
|
|
85
104
|
}
|
|
86
105
|
};
|
|
87
106
|
|
|
107
|
+
context.optimizeDependencies = optimizeDependencies(context);
|
|
88
108
|
context.readDotEnv = readDotEnv(context);
|
|
89
109
|
context.reloadClients = reloadClients(context);
|
|
90
110
|
context.restartServer = restartServer(context);
|
|
111
|
+
context.serverArtifacts = createServerArtifactTracker(context);
|
|
91
112
|
context.shutdownServer = shutdownServer(context);
|
|
92
113
|
context.startWatchers = startWatchers(context);
|
|
114
|
+
context.syncServer = syncServer(context);
|
|
93
115
|
|
|
94
116
|
return context;
|
|
95
117
|
}
|
|
@@ -15,12 +15,26 @@
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { pluginChecksNeedRebuild } from '@lowdefy/node-utils';
|
|
19
|
+
|
|
18
20
|
function initialBuild(context) {
|
|
19
21
|
return async () => {
|
|
20
22
|
context.readDotEnv();
|
|
21
23
|
await context.lowdefyBuild();
|
|
22
24
|
await context.checkMockUserWarning();
|
|
23
25
|
await context.installPlugins();
|
|
26
|
+
// The build lists the plugins it used but could not check, since they were
|
|
27
|
+
// not installed. The install above added them, so build once more when that
|
|
28
|
+
// checks something new, unless no checks run this time anyway.
|
|
29
|
+
if (
|
|
30
|
+
!context.options.skipPluginChecks &&
|
|
31
|
+
pluginChecksNeedRebuild({
|
|
32
|
+
buildDirectory: context.directories.build,
|
|
33
|
+
serverDirectory: context.directories.server,
|
|
34
|
+
})
|
|
35
|
+
) {
|
|
36
|
+
await context.lowdefyBuild();
|
|
37
|
+
}
|
|
24
38
|
};
|
|
25
39
|
}
|
|
26
40
|
|
|
@@ -0,0 +1,101 @@
|
|
|
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 fs from 'fs';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { jest } from '@jest/globals';
|
|
21
|
+
|
|
22
|
+
import initialBuild from './initialBuild.mjs';
|
|
23
|
+
|
|
24
|
+
let buildDirectory;
|
|
25
|
+
let calls;
|
|
26
|
+
|
|
27
|
+
function createContext({ installPlugins, skipPluginChecks } = {}) {
|
|
28
|
+
const record = (name, impl) =>
|
|
29
|
+
jest.fn(async () => {
|
|
30
|
+
calls.push(name);
|
|
31
|
+
if (impl) await impl();
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
directories: { build: buildDirectory, server: buildDirectory },
|
|
35
|
+
options: { skipPluginChecks },
|
|
36
|
+
readDotEnv: jest.fn(() => calls.push('readDotEnv')),
|
|
37
|
+
lowdefyBuild: record('lowdefyBuild'),
|
|
38
|
+
checkMockUserWarning: record('checkMockUserWarning'),
|
|
39
|
+
installPlugins: record('installPlugins', installPlugins),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
calls = [];
|
|
45
|
+
buildDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-initial-build-'));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
fs.rmSync(buildDirectory, { recursive: true, force: true });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('initialBuild builds once when no plugin checks are pending', async () => {
|
|
53
|
+
const context = createContext();
|
|
54
|
+
await initialBuild(context)();
|
|
55
|
+
expect(context.lowdefyBuild).toHaveBeenCalledTimes(1);
|
|
56
|
+
expect(calls).toEqual(['readDotEnv', 'lowdefyBuild', 'checkMockUserWarning', 'installPlugins']);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('initialBuild builds again after installing plugins when plugin checks are pending', async () => {
|
|
60
|
+
const context = createContext({
|
|
61
|
+
installPlugins: () =>
|
|
62
|
+
fs.writeFileSync(
|
|
63
|
+
path.join(buildDirectory, 'plugin-checks-pending.json'),
|
|
64
|
+
JSON.stringify({ packages: [{ name: '@acme/plugin', schemaChecked: true }] })
|
|
65
|
+
),
|
|
66
|
+
});
|
|
67
|
+
await initialBuild(context)();
|
|
68
|
+
expect(context.lowdefyBuild).toHaveBeenCalledTimes(2);
|
|
69
|
+
expect(calls).toEqual([
|
|
70
|
+
'readDotEnv',
|
|
71
|
+
'lowdefyBuild',
|
|
72
|
+
'checkMockUserWarning',
|
|
73
|
+
'installPlugins',
|
|
74
|
+
'lowdefyBuild',
|
|
75
|
+
]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('initialBuild builds once with skipPluginChecks, even when plugin checks are pending', async () => {
|
|
79
|
+
const context = createContext({
|
|
80
|
+
skipPluginChecks: true,
|
|
81
|
+
installPlugins: () =>
|
|
82
|
+
fs.writeFileSync(
|
|
83
|
+
path.join(buildDirectory, 'plugin-checks-pending.json'),
|
|
84
|
+
JSON.stringify({ packages: [{ name: '@acme/plugin', schemaChecked: true }] })
|
|
85
|
+
),
|
|
86
|
+
});
|
|
87
|
+
await initialBuild(context)();
|
|
88
|
+
expect(context.lowdefyBuild).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('initialBuild builds once when the pending plugins give nothing new to check', async () => {
|
|
92
|
+
const context = createContext({
|
|
93
|
+
installPlugins: () =>
|
|
94
|
+
fs.writeFileSync(
|
|
95
|
+
path.join(buildDirectory, 'plugin-checks-pending.json'),
|
|
96
|
+
JSON.stringify({ packages: [{ name: '@acme/connection', schemaChecked: false }] })
|
|
97
|
+
),
|
|
98
|
+
});
|
|
99
|
+
await initialBuild(context)();
|
|
100
|
+
expect(context.lowdefyBuild).toHaveBeenCalledTimes(1);
|
|
101
|
+
});
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { serializeBuildException, shallowBuild } from '@lowdefy/build/dev';
|
|
18
18
|
import createCustomPluginMessagesMap from '../utils/createCustomPluginMessagesMap.mjs';
|
|
19
19
|
import createCustomPluginTypesMap from '../utils/createCustomPluginTypesMap.mjs';
|
|
20
|
+
import publishBuildDirectory from '../utils/publishBuildDirectory.mjs';
|
|
20
21
|
import writeBuildStatus from '../utils/writeBuildStatus.mjs';
|
|
21
22
|
|
|
22
23
|
function formatDuration(ms) {
|
|
@@ -25,26 +26,39 @@ function formatDuration(ms) {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
function lowdefyBuild({ directories, logger, options }) {
|
|
28
|
-
|
|
29
|
+
async function build() {
|
|
29
30
|
logger.info({ spin: 'start' }, 'Building config...');
|
|
30
31
|
const startTime = Date.now();
|
|
31
|
-
const customTypesMap = await createCustomPluginTypesMap({ directories, logger });
|
|
32
|
-
const customMessagesMap = await createCustomPluginMessagesMap({ directories, logger });
|
|
33
32
|
|
|
33
|
+
// Reading the plugin maps parses lowdefy.yaml and imports each plugin's
|
|
34
|
+
// types, so a YAML syntax error or a broken plugin fails the build there,
|
|
35
|
+
// and the build status has to report it like any other build error. So
|
|
36
|
+
// does a publish that fails part way: the live build is then a mix of two
|
|
37
|
+
// builds, and the next change must rebuild and publish it whole.
|
|
34
38
|
let result;
|
|
35
39
|
try {
|
|
40
|
+
const [customTypesMap, customMessagesMap] = await Promise.all([
|
|
41
|
+
createCustomPluginTypesMap({ directories, logger }),
|
|
42
|
+
createCustomPluginMessagesMap({ directories, logger }),
|
|
43
|
+
]);
|
|
36
44
|
result = await shallowBuild({
|
|
37
45
|
customMessagesMap,
|
|
38
46
|
customTypesMap,
|
|
39
|
-
directories,
|
|
47
|
+
directories: { ...directories, build: directories.buildStaging },
|
|
40
48
|
logger,
|
|
41
49
|
refResolver: options.refResolver,
|
|
50
|
+
skipPluginChecks: options.skipPluginChecks,
|
|
42
51
|
stage: 'dev',
|
|
43
52
|
});
|
|
53
|
+
await publishBuildDirectory({
|
|
54
|
+
buildDirectory: directories.build,
|
|
55
|
+
stagingDirectory: directories.buildStaging,
|
|
56
|
+
}).catch((error) => {
|
|
57
|
+
throw new Error(`Publishing the build to ${directories.build} failed: ${error.message}`, {
|
|
58
|
+
cause: error,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
44
61
|
} catch (error) {
|
|
45
|
-
// Write the artifact after the attempt fails - the build may have
|
|
46
|
-
// cleaned the build directory before failing, so this must not run
|
|
47
|
-
// before the attempt completes.
|
|
48
62
|
await writeBuildStatus({
|
|
49
63
|
directories,
|
|
50
64
|
status: 'error',
|
|
@@ -65,6 +79,15 @@ function lowdefyBuild({ directories, logger, options }) {
|
|
|
65
79
|
const duration = Date.now() - startTime;
|
|
66
80
|
logger.info({ spin: 'succeed' }, `Built config in ${formatDuration(duration)}.`);
|
|
67
81
|
return result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Watchers, restarts and plugin installs each start builds, and every build
|
|
85
|
+
// writes the same staging directory, so a build waits for the one before it.
|
|
86
|
+
let previousBuild = Promise.resolve();
|
|
87
|
+
return () => {
|
|
88
|
+
const nextBuild = previousBuild.then(build);
|
|
89
|
+
previousBuild = nextBuild.catch(() => {});
|
|
90
|
+
return nextBuild;
|
|
68
91
|
};
|
|
69
92
|
}
|
|
70
93
|
|
|
@@ -0,0 +1,62 @@
|
|
|
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 { jest } from '@jest/globals';
|
|
18
|
+
|
|
19
|
+
const mockShallowBuild = jest.fn();
|
|
20
|
+
|
|
21
|
+
jest.unstable_mockModule('@lowdefy/build/dev', () => ({
|
|
22
|
+
shallowBuild: mockShallowBuild,
|
|
23
|
+
serializeBuildException: jest.fn((exception) => ({ message: exception.message })),
|
|
24
|
+
}));
|
|
25
|
+
jest.unstable_mockModule('../utils/writeBuildStatus.mjs', () => ({
|
|
26
|
+
default: jest.fn(),
|
|
27
|
+
}));
|
|
28
|
+
jest.unstable_mockModule('../utils/createCustomPluginTypesMap.mjs', () => ({
|
|
29
|
+
default: jest.fn().mockResolvedValue({}),
|
|
30
|
+
}));
|
|
31
|
+
jest.unstable_mockModule('../utils/createCustomPluginMessagesMap.mjs', () => ({
|
|
32
|
+
default: jest.fn().mockResolvedValue({}),
|
|
33
|
+
}));
|
|
34
|
+
jest.unstable_mockModule('../utils/publishBuildDirectory.mjs', () => ({
|
|
35
|
+
default: jest.fn(async () => {}),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const { default: lowdefyBuild } = await import('./lowdefyBuild.mjs');
|
|
39
|
+
|
|
40
|
+
function createContext(options) {
|
|
41
|
+
return {
|
|
42
|
+
directories: { build: '/app/build', buildStaging: '/app/build-staging' },
|
|
43
|
+
logger: { info: jest.fn() },
|
|
44
|
+
options,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
mockShallowBuild.mockResolvedValue({ components: {}, pageRegistry: {}, context: {} });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('lowdefyBuild passes skipPluginChecks true to shallowBuild', async () => {
|
|
53
|
+
await lowdefyBuild(createContext({ skipPluginChecks: true }))();
|
|
54
|
+
expect(mockShallowBuild.mock.calls[0][0].skipPluginChecks).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('lowdefyBuild passes skipPluginChecks undefined to shallowBuild when the option is not set', async () => {
|
|
58
|
+
await lowdefyBuild(createContext({}))();
|
|
59
|
+
const [args] = mockShallowBuild.mock.calls[0];
|
|
60
|
+
expect(args.skipPluginChecks).toBeUndefined();
|
|
61
|
+
expect(args.stage).toEqual('dev');
|
|
62
|
+
});
|
|
@@ -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
|
+
});
|